sách gpt4 ăn đã đi

Thảo luận ngắn gọn về mẫu Khách truy cập trong C++ 17

In lại Tác giả: qq735679552 Thời gian cập nhật: 27-09-2022 22:32:09 27 4
mua khóa gpt4 giày nike

CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.

Bài viết trên blog CFSDN này nói sơ qua về mẫu Visitor trong C++17 được tác giả sưu tầm và biên soạn. Nếu các bạn quan tâm đến bài viết này thì nhớ like nhé.

1、Mẫu khách truy cập

Mẫu khách truy cập là mẫu hành vi cho phép bất kỳ khách truy cập tách biệt nào truy cập các phần tử được quản lý dưới sự kiểm soát của quản trị viên. Khách truy cập không thể thay đổi định nghĩa của đối tượng (nhưng điều này không bắt buộc, bạn có thể đồng ý cho phép thay đổi). Đối với người quản lý, nó không quan tâm đến việc có bao nhiêu khách truy cập, nó chỉ quan tâm đến thứ tự truy cập nhất định của các phần tử (ví dụ: đối với cây nhị phân, bạn có thể cung cấp nhiều thứ tự truy cập như in-order và pre-order) .

Thảo luận ngắn gọn về mẫu Khách truy cập trong C++ 17

1. Thành phần

Mẫu Khách truy cập chứa hai đối tượng chính: Đối tượng có thể truy cập và đối tượng Khách truy cập. Ngoài ra, các đối tượng Đã truy cập cũng được đưa vào chế độ Khách truy cập dưới dạng các đối tượng cần thao tác.

Một đối tượng có thể truy cập, tức là người quản lý, có thể chứa một loạt các phần tử (Đã truy cập) có nhiều hình dạng khác nhau, có thể có các mối quan hệ cấu trúc phức tạp trong Có thể truy cập (nhưng nó cũng có thể là một mối quan hệ chỗ ở đơn giản, chẳng hạn như một vectơ đơn giản). Có thể truy cập nói chung là một vùng chứa phức tạp chịu trách nhiệm diễn giải các mối quan hệ này và duyệt qua các phần tử này bằng logic tiêu chuẩn. Khi Có thể truy cập lặp lại các phần tử này, nó cung cấp từng phần tử cho Khách truy cập để nó có thể truy cập phần tử Đã truy cập.

Mẫu lập trình như vậy là Mẫu khách truy cập.

2. Giao diện

Để có thể quan sát mọi phần tử, thực tế phải có một ràng buộc: tất cả các phần tử có thể quan sát được đều có một lớp cơ sở chung là Visited.

Tất cả Khách truy cập phải được bắt nguồn từ Khách truy cập để cung cấp giao diện Visitable.accept(visitor&).

không gian tên hicc::util { struct base_visitor { virtual ~base_visitor() {} }; struct base_visitable { virtual ~base_visitable() {} }; template lớp visitor : public base_visitor { public: sử dụng return_t = ReturnType; sử dụng visited_t = std::unique_ptr<đã ghé="" thăm="">; virtual return_t visit(visited_t const &visited) = 0; }; template lớp visitable : public base_visitable { public: virtual ~visitable() {} sử dụng return_t = ReturnType; sử dụng visitor_t = visitor<đã ghé="" thăm,="" return_t="">; virtual return_t accept(visitor_t &guest) = 0; };} // không gian tên hicc::util

3. Cảnh

Ví dụ: giả sử chúng ta đang thiết kế một bộ trình soạn thảo đồ họa vector. Trong Canvas, có thể có nhiều lớp (Layer), mỗi lớp chứa một số thuộc tính nhất định (chẳng hạn như màu tô, độ trong suốt) và có thể có nhiều loại phần tử. . Nguyên thủy có thể là Point, Line, Rect, Arc, v.v.

Để có thể vẽ canvas lên màn hình, chúng ta có thể có một đối tượng thiết bị Screen, thực hiện giao diện Visitor, để canvas có thể chấp nhận quyền truy cập từ Screen để vẽ các phần tử trong canvas ra màn hình.

Nếu chúng tôi cung cấp Máy in làm người quan sát, khung vẽ sẽ có thể in các bản gốc.

Nếu chúng tôi cung cấp Tài liệu với tư cách là người quan sát, khung vẽ sẽ có thể tuần tự hóa các thuộc tính nguyên thủy thành một tệp đĩa.

Nếu cần các hành vi khác trong tương lai, chúng ta có thể tiếp tục thêm người quan sát mới và thực hiện các thao tác tương tự trên canvas và các nguyên mẫu của nó.

4. Tính năng

  • Nếu bạn cần thực hiện một số thao tác trên tất cả các thành phần trong cấu trúc đối tượng phức tạp (chẳng hạn như cây đối tượng), hãy sử dụng mẫu khách truy cập.
  • Mẫu khách truy cập trừu tượng hóa các chức năng không chính khỏi trình quản lý đối tượng, do đó, nó cũng là một phương tiện tách rời.
  • Nếu bạn đang tạo một thư viện lớp thư viện đối tượng, thì việc cung cấp giao diện truy cập ra bên ngoài sẽ giúp người dùng phát triển khách truy cập của riêng họ để truy cập thư viện lớp của bạn mà không bị xâm phạm - anh ta không cần phải đưa nó cho bạn vì vấn đề nhỏ của mình/. kéo yêu cầu.
  • Đối với các tình huống ở đó mức cấu trúc phức tạp, bạn phải giỏi sử dụng khả năng lồng đối tượng và đệ quy để tránh viết logic tương tự nhiều lần.

Vui lòng xem cách triển khai tham chiếu của canvas, lớp và nhóm. Chúng triển khai các khả năng tự quản lý lồng nhau bằng cách triển khai drawable và vistiable, đồng thời cho phép chấp nhận() để nhập đệ quy từng vùng chứa.

5. Nhận ra

Chúng tôi sử dụng một phần của trình soạn thảo vectơ làm ví dụ để triển khai nó, sử dụng mẫu lớp cơ bản được đưa ra trước đó.

có thể vẽ và nguyên thủy cơ bản.

Đầu tiên hãy khai báo cơ bản về hình vẽ/hình dạng và các nguyên hàm cơ bản:

không gian tên hicc::dp::visitor::basic {sử dụng draw_id = std::size_t;/** @brief một hình dạng như một chấm, một đường thẳng, một hình chữ nhật, v.v. */struct drawable { virtual ~drawable() {} friend std::ostream &operator<<(std::ostream &os, drawable const *o) { return os << '<' << o->type_name() << '#' << o->id() << '>'; } virtual std::string type_name() const = 0; draw_id id() const { return _id; } void id(draw_id id_) { _id = id_; } private: draw_id _id;};#define MAKE_DRAWABLE(T) \ T(draw_id id_) { id(id_); } \ T() {} \ ảo ~T() {} \ std::string type_name() const ghi đè { \ trả về std::string{hicc::debug::type_name()}; \ } \ bạn bè std::ostream &operator<<(std::ostream &os, T const &o) { \ trả về os << '<' << o.type_name() << '#' << o.id() << '>'; \ }//@formatter:offstruct point : public drawable {MAKE_DRAWABLE(point)};struct line : public drawable {MAKE_DRAWABLE(line)};struct rect : public drawable {MAKE_DRAWABLE(rect)};struct ellipse : public drawable {MAKE_DRAWABLE(ellipse)};struct arc : public drawable {MAKE_DRAWABLE(arc)};struct triangle : public drawable {MAKE_DRAWABLE(triangle)};struct star : public drawable {MAKE_DRAWABLE(star)};struct polygon : public drawable {MAKE_DRAWABLE(polygon)};struct text : public drawable {MAKE_DRAWABLE(text)};//@formatter:on// lưu ý: dot, rect (line, rect, elip, arc, text), poly (tam giác, sao, đa giác)}

Vì mục đích gỡ lỗi, chúng tôi đã nạp chồng toán tử đầu ra luồng '<<' và sử dụng macro MAKE_DRAWABLE để giảm số lần nhấn phím cho mã lặp lại. Trong macro MAKE_DRAWABLE, chúng tôi lấy tên lớp thông qua hicc::debug::type_name() và trả về tên này dưới dạng chuỗi từ drawable::type_name().

Vì lý do đơn giản, các đối tượng nguyên thủy cơ bản không có thứ bậc mà có nguồn gốc song song từ đối tượng có thể vẽ được.

Tổng hợp các lớp và nguyên thủy.

Phần sau đây khai báo đối tượng nhóm, chứa một nhóm nguyên thủy. Vì chúng ta muốn có càng nhiều cấu trúc đệ quy càng tốt, nên một lớp cũng được coi là một thành phần của một tập hợp nguyên thủy:

không gian tên hicc::dp::visitor::basic {struct nhóm: public drawable, public hicc::util::visitable { MAKE_DRAWABLE(nhóm) sử dụng drawable_t = std::unique_ptr; sử dụng drawables_t = std::unordered_map; drawables_t drawables; void add(drawable_t &&t) { drawables.emplace(t->id(), std::move(t)); } return_t accept(visitor_t &guest) override { for (auto const &[did, dr] : drawables) { guest.visit(dr); UNUSED(did); } }};struct layer: public group { MAKE_DRAWABLE(lớp) // thêm: attrs, ...};}

Giao diện có thể truy cập đã được triển khai trong lớp nhóm và việc chấp nhận của nó có thể chấp nhận quyền truy cập từ khách truy cập. Tại thời điểm này, nhóm nhóm nguyên thủy sẽ duyệt qua tất cả các nguyên thủy của nó và cung cấp chúng cho khách truy cập.

Chúng ta cũng có thể tạo một kiểu nguyên thủy phức hợp dựa trên lớp nhóm, cho phép kết hợp một số kiểu nguyên thủy thành một thành phần nguyên thủy mới. Sự khác biệt giữa hai loại này là nhóm thường là một đối tượng tạm thời trong các hoạt động giao diện người dùng, trong khi các kiểu nguyên thủy hỗn hợp có thể được sử dụng. Là thành viên của thư viện thành phần để người dùng lựa chọn và sử dụng. Theo mặc định, khách sẽ truy cập các nguyên thủy ở dạng const & đã truy cập, ở chế độ chỉ đọc.

Lớp này ít nhất có tất cả các khả năng của nhóm, vì vậy nó hoạt động giống nhau đối với khách truy cập. Các thuộc tính của lớp (mặt nạ, lớp phủ, v.v.) bị bỏ qua.

Vải bạt.

Canvas chứa một số lớp, do đó, nó cũng sẽ triển khai giao diện có thể truy cập:

không gian tên hicc::dp::visitor::basic {struct canvas : public hicc::util::visitable { sử dụng layer_t = std::unique_ptr; sử dụng layers_t = std::unordered_map; layers_t layers; void add(draw_id id) { layers.emplace(id, std::make_unique(id)); } layer_t &get(draw_id id) { trả về layers[id]; } layer_t &operator[](draw_id id) { trả về layers[id]; } virtual return_t accept(visitor_t &guest) override { // hicc_debug("[canva] đang truy cập: %s", to_string(guest).c_str()); for (auto const &[lid, ly] : layers) { ly->accept(guest); } return; }};}

Trong số đó, add sẽ tạo một lớp mới với các tham số mặc định và thứ tự lớp tuân theo phương pháp xếp chồng lên trên. Các toán tử get và [] có thể truy cập một lớp thông qua chỉ số dưới số nguyên dương. Tuy nhiên, mã không bao gồm chức năng quản lý thứ tự lớp. Nếu quan tâm, bạn có thể thêm cấu trúc phụ trợ std::vector để giúp quản lý thứ tự lớp.

Bây giờ hãy xem lại hệ thống canvas-layer-prime. Giao diện chấp nhận chạy thành công trên toàn bộ hệ thống.

Đã đến lúc xây dựng du khách.

màn hình hoặc máy in.

Hai cái này thực hiện giao diện khách truy cập đơn giản:

không gian tên hicc::dp::visitor::basic {struct screen : public hicc::util::visitor { return_t visit(visited_t const &visited) override { hicc_debug("[screen][draw] for: %s", to_string(visited.get()).c_str()); } friend std::ostream &operator<<(std::ostream &os, screen const &) { return os << "[screen] "; }};struct printer : public hicc::util::visitor { return_t visit(visited_t const &visited) override { hicc_debug("[printer][draw] for: %s", to_string(visited.get()).c_str()); } friend std::ostream &operator<<(std::ostream &os, printer const &) { return os << "[printer] "; }};}

hicc::to_string là một trình bao bọc luồng đơn giản thực hiện logic cốt lõi sau:

mẫuinline std::string to_string(T const &t) {std::stringstream ss;ss << t;return ss.str();}

trường hợp thử nghiệm 。

Chương trình thử nghiệm xây dựng một khung vẽ thu nhỏ và một số nguyên mẫu, sau đó truy cập chúng theo sơ đồ:

void test_visitor_basic() { sử dụng không gian tên hicc::dp::visitor::basic; canvas c; static draw_id id = 0, did = 0; c.add(++id); // thêm một lớp đồ thị c[1]->add(std::make_unique(++did)); c[1]->add(std::make_unique(++did)); c[1]->add(std::make_unique(++did)); screen scr; c.accept(scr);}

Đầu ra sẽ trông giống như thế này:

--- BẮT ĐẦU CỦA test_visitor_basic ---------------------- 14/09/21 00:33:31 [gỡ lỗi]: [màn hình][vẽ] cho:  14/09/21 00:33:31 [gỡ lỗi]: [màn hình][vẽ] cho:  14/09/21 00:33:31 [gỡ lỗi]: [màn hình][vẽ] cho: 

  。

2、Lời kết

Mẫu Visitor đôi khi có thể được thay thế bằng mẫu Iterator. Nhưng các trình vòng lặp thường có một lỗ hổng nghiêm trọng làm hạn chế tính hữu dụng của chúng: bản thân các trình vòng lặp có thể cứng nhắc, đắt tiền và kém hiệu quả—trừ khi bạn đưa ra các lựa chọn về thời gian thiết kế phù hợp nhất và triển khai trình vòng lặp thanh lịch nhất. Cả hai đều cho phép người dùng truy cập nội dung của một vùng chứa phức tạp đã biết mà không bị xâm nhập.

Đến đây là kết thúc bài viết này về chế độ Khách truy cập trong C++ 17. Để biết thêm thông tin về chế độ Khách truy cập trong C++ 17, vui lòng tìm kiếm các bài viết trước của tôi hoặc tiếp tục duyệt các bài viết liên quan bên dưới. tương lai! .

Liên kết gốc: https://segmentfault.com/a/1190000040679433.

Cuối cùng, bài viết về chế độ Khách truy cập trong C++ 17 kết thúc tại đây. Nếu bạn muốn biết thêm về chế độ Khách truy cập trong C++ 17, vui lòng tìm kiếm các bài viết về CFSDN hoặc tiếp tục duyệt các bài viết liên quan, hy vọng bạn sẽ ủng hộ. blog của tôi trong tương lai! .

27 4 0
qq735679552
Hồ sơ

Tôi là một lập trình viên xuất sắc, rất giỏi!

Nhận phiếu giảm giá taxi Didi miễn phí
Phiếu giảm giá taxi Didi
Chứng chỉ ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com
Xem sitemap của VNExpress