C++ Object slice

本文深入探讨了C++中对象切片(Object Slicing)的概念及其潜在问题。通过具体示例展示了如何在使用STL容器时避免对象切片,特别是在涉及多态类的情况下。解释了为何直接将派生类对象复制给基类对象会导致派生部分丢失,并提供了代码实例加以说明。

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

第一次遇到这个名词(Object slice)在meyers的Effective STL中。有一条忠告:
不要尝试使用STL容器,管理多态的类对象。类似:

class Base{
public:
virtual void fun(){cout << "Base" << endl;}
};
class Derived1 : public Base {
public:
virtual void fun(){cout << "Derived1" << endl;}
};
class Derived2 : public Base {
public:
virtual void fun(){cout << "Derived2" << endl;}
};

void main()
{
    vector<Base> vb;
    Derived1 d1;
    Derived2 d2;
    vb.push_back(d1);
    vb.push_back(d2);

    vb[0].fun();
    vb[1].fun();
}

以上两次调用fun(),输出结果均为”Base”。原因就是在vb.push_back时发生了“object slice“。
换句话说,如果向基类对象建立一个容器中插入派生类对象,那么当对象放入容器的时候对象的派生部分不会被复制进容器。

注:可以看出STL管理对象的方式,无论是将对象放入容器,还是从容器中拿出对象(当然不包括operator[]),都是以复制的方式。即,如果insert或push_back(obj),放入容器的不是obj自己,而是obj的一个拷贝。

再说回Object slice,《Inside the C++ Object Model》中介绍是为什么会产生Object slice。简单的说就是,当你将一个派生类对象复制给基类对象时,为了保证内存空间的正确性,编译器只能将派生类对象切割,填充到基类对象的内存空间中(同时,虚表不会被重新赋值)。派生部分就是被切割的那部分。

相同道理,以下代码也会发生object slice:

void main()
{
    Base bs;
    Derived1 dv1;
    bs = dv1; // dv1会被slice
    bs.fun(); // 会输出 Base
}
ICE(Internet Communications Engine)是一个先进的面向对象的中间件平台,用于构建分布式应用程序。它由ZeroC公司开发,提供了跨平台、跨语言的通信能力,特别适合需要高性能和可扩展性的场景。以下是关于ICE C++使用指南和示例的详细介绍。 ### ICE C++ 开发基础 #### 1. 安装与配置 在开始使用ICE进行C++开发之前,首先需要安装ICE的C++运行时库和开发工具。可以从[ZeroC官网](https://zeroc.com/)下载适用于不同操作系统的ICE发行版。对于Linux系统,通常可以通过包管理器安装: ```bash sudo apt-get install libzeroc-ice3.7-dev ``` 安装完成后,确保编译器能够找到ICE的头文件和库文件。通常需要设置`CPATH`和`LIBRARY_PATH`环境变量,或者在编译命令中指定包含路径和链接库。 #### 2. 编写第一个ICE应用 ICE的核心概念是对象和接口。开发者需要首先定义接口,然后实现服务端和客户端。 ##### 定义接口(`Hello.ice`) ```ice module Demo { interface Hello { void sayHello(); }; }; ``` ##### 生成C++代码 使用`slice2cpp`工具将`.ice`文件转换为C++代码: ```bash slice2cpp Hello.ice ``` 这将生成`Hello.h`和`Hello.cpp`文件,包含接口的桩(stub)和骨架(skeleton)代码。 ##### 实现服务端(`Server.cpp`) ```cpp #include <Ice/Ice.h> #include <Hello.h> class HelloI : public Demo::Hello { public: virtual void sayHello(const Ice::Current&) override { std::cout << "Hello World!" << std::endl; } }; int main(int argc, char* argv[]) { int status = 0; Ice::CommunicatorPtr ic; try { ic = Ice::initialize(argc, argv); Ice::ObjectAdapterPtr adapter = ic->createObjectAdapterWithEndpoints("HelloAdapter", "default -p 10000"); Ice::ObjectPtr object = new HelloI; adapter->add(object, ic->stringToIdentity("hello")); adapter->activate(); ic->waitForShutdown(); } catch (const std::exception& ex) { std::cerr << ex.what() << std::endl; status = 1; } if (ic) ic->destroy(); return status; } ``` ##### 实现客户端(`Client.cpp`) ```cpp #include <Ice/Ice.h> #include <Hello.h> int main(int argc, char* argv[]) { int status = 0; Ice::CommunicatorPtr ic; try { ic = Ice::initialize(argc, argv); Ice::ObjectPrx base = ic->stringToProxy("hello:default -h localhost -p 10000"); Demo::HelloPrx hello = Demo::HelloPrx::checkedCast(base); if (!hello) throw std::runtime_error("Invalid proxy"); hello->sayHello(); } catch (const std::exception& ex) { std::cerr << ex.what() << std::endl; status = 1; } if (ic) ic->destroy(); return status; } ``` ##### 编译与运行 服务端和客户端的编译命令如下: ```bash g++ -o server Server.cpp Hello.cpp -lIce -lIceUtil g++ -o client Client.cpp Hello.cpp -lIce -lIceUtil ``` 启动服务端: ```bash ./server ``` 在另一个终端运行客户端: ```bash ./client ``` 如果一切正常,客户端将输出“Hello World!”。 ### ICE C++ 高级特性 #### 1. 异步调用 ICE支持异步方法调用,允许客户端在等待服务端响应的同时继续执行其他任务。可以通过在接口定义中使用`async`关键字来启用异步调用。 #### 2. 对象生命周期管理 ICE提供了多种机制来管理远程对象的生命周期,包括对象适配器、对象标识符和对象激活策略。开发者可以根据应用程序的需求选择合适的策略。 #### 3. 安全性 ICE支持SSL/TLS加密通信,确保数据在传输过程中的安全性。可以通过配置端点来启用SSL: ```cpp adapter = ic->createObjectAdapterWithEndpoints("SecureHelloAdapter", "ssl -p 10001"); ``` #### 4. 分布式部署 ICE支持跨网络的分布式部署,允许服务端和客户端位于不同的物理或虚拟主机上。通过配置正确的网络地址和端口,可以轻松实现远程调用。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值