Essential C++ 学习笔记(五)

本文深入探讨了面向对象编程的核心概念,包括继承、多态和动态绑定,并详细解析了面向对象编程思维、抽象基类和派生类的定义及应用。通过实例阐述了如何在派生类中定义虚拟函数,以及基类如何多抽象化以提高代码复用性和灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

5.1 面向对象编程概念

1. 面向对象风格的三个独特概念: 继承(inheritance), 多态(polymorphism), 动态绑定(Dynamic binding).

2. 多态和动态绑定的特性, 只有在使用pointer或reference时才能发挥.


5.2 面向对象编程思维

1. 当程序定义出一个派生对象时, 基类和派生类的constructor都会被执行起来. 但派生类被摧毁时,  基类和派生类的destructor

也都会被执行起来(但次序颠倒).

2. 基类被声明为protected 的所有成员都可以被派生类直接取用, 除此派生类之外, 都不得直接用protected 成员.

3. 使用派生类不需刻意区分"继承而来的成员"和"自身定义的成员", 两者的使用完全透明.


5.4 定义一个抽象基类

1. 定义抽象类的第一个步骤是找出所有子类共通的操作行为.

    第二步是找出哪些行为与型别相依, 也就是说, 有哪些操作行为必须根据不同的派生类而有不同的实现方式.

    第三步是试着找出每个操作行为的存取层级.


2. 每个虚拟函数, 必须有其定义. 如果对于该类而言, 这个虚拟函数并无实质意义的话, 那么可设为纯虚拟函数 (pure virtual function).

凡基类定义有一个或多个虚拟函数, 应该要将其destructor声明为virtual.


5.5 定义一个派生类

1. 在类本身之外对虚拟函数进行定义时, 不需指明关键词virtual.

2. 最好跳过虚拟函数机制, 是该函数在编译期就完成决议, 不需等到执行期才决议, 这就是为什么要指明调用对象的原因.

3. 每当派生类的某个member与基类的member同名时, 便会遮蔽住基类的那份member. 在基类和派生类中提供同名的non-virtual 函数,

并不是好的解决方法.


5.7 基类应该多抽象

1. data members 如果是个reference, 则必须在constructor的 member initialization list中加以初始化. 如果data members 是个pointer,就无此限制:

可以在constructor内加以初始化, 也可以先将它初始化为null, 稍后再令他指向某个有效的内存地址.


5.9 在派生类中定义一个虚拟函数

1. 在派生类中, 为了改写基类的某个虚拟函数, 而进行声明操作时,不一定要加上关键词virtual.

2. 在基类得constructor中, 派生类的虚拟函数绝对不会被调用.

3. 多态需要一层间接性, 唯有以基类的pointers和references才能支持面向编程的概念.


### C++ gRPC 学习教程示例代码 #### 一、环境搭建 为了能够顺利运行C++中的gRPC程序,需要先完成开发环境的配置。这通常涉及到安装必要的依赖库以及设置编译工具链。具体来说,可以按照官方文档指导来准备所需的软件包,比如Protocol Buffers编译器`protoc`及其对应的C++插件,还有gRPC核心库等[^1]。 ```bash sudo apt-get install build-essential autoconf libtool pkg-config git clone https://github.com/protocolbuffers/protobuf.git cd protobuf ./autogen.sh && ./configure && make -j$(nproc) && sudo make install ``` 对于gRPC本身,则可以通过如下命令获取并构建: ```bash git clone --recurse-submodules -b v1.48.x https://github.com/grpc/grpc cd grpc mkdir -p cmake/build && cd cmake/build cmake ../.. make -j$(nproc) sudo make install ``` #### 二、创建Protobuf文件 接下来就是定义服务接口,在`.proto`文件里描述消息结构服务方法。这里给出一个简单的例子——HelloWorld服务,其中包含了一个名为SayHello的方法用于接收请求并向客户端返回响应信息。 ```protobuf syntax = "proto3"; option cc_enable_arenas = true; package helloworld; // The greeting service definition. service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } // The request message containing the user's name. message HelloRequest { string name = 1; } // The response message containing the greetings message HelloReply { string message = 1; } ``` 保存上述内容到`helloworld.proto`之后,利用之前提到过的`protoc`命令行工具将其转换成相应的头文件与源码文件以便后续使用。 #### 三、编写服务器端逻辑 基于前面所生成的服务模板,现在可以在项目中实现具体的业务处理函数了。下面展示的是如何继承自动生成出来的基,并重写虚函数以提供实际功能的部分代码片段。 ```cpp #include <iostream> #include "helloworld.grpc.pb.h" using namespace std; using grpc::Server; using grpc::ServerBuilder; using grpc::ServerContext; using grpc::Status; using helloworld::Greeter; using helloworld::HelloReply; using helloworld::HelloRequest; class GreeterServiceImpl final : public Greeter::Service { public: Status SayHello(ServerContext* context, const HelloRequest* request, HelloReply* reply) override { string prefix("Hello "); reply->set_message(prefix + request->name()); return Status::OK; } }; ``` 这段代码实现了当接收到客户端发起的调用时会执行的操作:拼接字符串形成回复文本并通过参数传递给对方。 #### 四、启动监听进程 有了完整的协议声明加上对应的功能模块后就可以着手建立网络连接等待远端访问啦! ```cpp void RunServer() { string server_address("0.0.0.0:50051"); GreeterServiceImpl service; ServerBuilder builder; // Listen on the given address without any authentication mechanism. builder.AddListeningPort(server_address, grpc::InsecureServerCredentials()); // Register "service" as the instance through which we'll communicate with // clients. In this case it corresponds to an *synchronous* service. builder.RegisterService(&service); // Finally assemble the server. unique_ptr<Server> server(builder.BuildAndStart()); cout << "Server listening on " << server_address << endl; // Wait for the server to shutdown. Note that some other thread must be // responsible for shutting down the server for this call to ever return. server->Wait(); } ``` 此部分负责初始化HTTP/2传输层设施并将指定地址开放出去供外界联系;同时注册好先前定义好的处理器对象使得每次有新链接进来都能找到合适的地方去解析数据流进而触发相应动作。 #### 、客户端编程指南 最后一步自然是要让应用程序具备主动出击的能力咯~即构造出能向远程主机发出请求的消息体格式化为wire format再经由socket发送过去得到回应为止的过程。 ```cpp void RunClient() { string target_str("localhost:50051"); // Instantiate the client. It requires a channel, out of which the actual RPCs // are created. This channel models a connection to an endpoint specified by // the argument; you may provide extra arguments to indicate credentials, // compression Level etc. shared_ptr<Channel> channel = CreateChannel(target_str, InsecureChannelCredentials()); // Stub acts like a proxy object representing remote side entity. unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel)); // Data we are sending to the server. HelloRequest request; request.set_name("you"); // Container for the data we expect from the server. HelloReply reply; // Context for the client. It could be used to convey extra information to // the server and/or tweak certain RPC behaviors. ClientContext context; // The actual RPC. Status status = stub->SayHello(&context, request, &reply); // Act upon its status. if (status.ok()) { cout << "Greeter received: " << reply.message() << endl; } else { cerr << status.error_code() << ": " << status.error_message() << endl; } } ``` 以上便是整个流程的大致介绍,当然这只是冰山一角而已,更多高级特性最佳实践还需要读者朋友们自行探索学习哦~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值