C++:赋值运算符和多重继承

举报
陈方业 发表于 2021/08/10 10:08:40 2021/08/10
【摘要】 在开源poco库的Socket类继承使用过程中,由于赋值运算符和多重继承出现了问题,因此模拟poco库源码写了一个测试用例,理解一下赋值运算符和多重继承等C++概念,如果有错误理解之处,请指出。
#include <iostream>
using namespace std;


class Socket
{
public:
    Socket(int flags): _flags(flags){ cout << "Socket constructor" << " _flags pointer: " << &_flags << endl;}

    Socket& operator = (const Socket& socket) 
    {
        cout << "Socket assignment operationer. _flags = " << _flags << ", _flags pointer : " << &_flags << ", socket._flags = " << socket._flags << ", socket._flags pointer : " << &(socket._flags) << endl; 
        _flags = socket._flags;
        return *this;
    }

    int getFlags() {
        return _flags;
    }

private:
    int _flags = 0;
};

class StreamSocket: public Socket
{
public:
    StreamSocket(): Socket(1){ cout << "StreamSocket(1) constructor" << endl; }
    StreamSocket(int flags): Socket(flags) {cout << "StreamSocket(flags) constructor" << endl;}

    StreamSocket& operator = (const Socket& socket) 
    {
        cout << "StreamSocket assignment operationer" << endl;
        Socket::operator = (socket);
        return *this;
    }
};

class SecureStreamSocket: public StreamSocket
{
public:
    SecureStreamSocket(): StreamSocket(2){ cout << "SecureStreamSocket(2) constructor" << endl;}

    SecureStreamSocket& operator = (const Socket& socket)
    {
        StreamSocket::operator = (socket);
        cout << "SecureStreamSocket assignment operationer" << endl; 
        return *this;
    }
};

class ZkStreamSocket: public StreamSocket
{
};

class ZkSecureStreamSocket : public ZkStreamSocket, public SecureStreamSocket
{
public:
    using SecureStreamSocket::SecureStreamSocket;
};

/*
*   总结:
*       1:ZkSecureStreamSocket的内存分布包含了ZkStreamSocket和SecureStreamSocket两块,因此也包含了两块Socket和它的成员变量_flags;
*   2:由于赋值运算符不属于函数重写,其调用依赖于左值类型。同时,在调用赋值运算符的时候找不到参数匹配的赋值运算符,因此各个子类会生成
*   默认赋值运算符并且在默认赋值运算符中调用父类的赋值运算符。所以我们能看到最终调用到的都是Socket::operator =(Socket)(只要左值类
*   不是右值类的派生类);3:在test1和test2的对比中,多重继承的右值对象根据左值类型将内存中的对应的Socket::_flags在Socket类中拷贝
*   给左值。
*/
int main()
{
    /*几个类中的赋值运算符看起来既不属于函数重载也不属于函数重写*/
    /*test 1: https://stackoverflow.com/questions/8894090/derived-class-inherit-base-class-assignment-operator*/
    /*反编译查看代码流程:https://www.cnblogs.com/skynet/archive/2010/09/05/1818636.html*/
    ZkStreamSocket socket; // 菱形继承
    cout << socket.getFlags() << endl;   // 1
    socket = ZkSecureStreamSocket();     // 改成ZkStreamSocket结果是一样的
    cout << socket.getFlags() << endl;   // 1

    /*test 2*/
    // SecureStreamSocket socket;  // 菱形继承, 更改左值类型, 和上面结果对比,根据左值类型(基类作用域)进行子类给基类赋值(SecureStreamSocket和ZkStreamSocket是菱形继承的基类)?
    // cout << socket.getFlags() << endl;   // 2
    // socket = ZkSecureStreamSocket();
    // cout << socket.getFlags() << endl;   // 2

    /*test 3: https://www.codenong.com/cs106790463/*/
    // StreamSocket socket;   // 非菱形继承, 子类和父类互相赋值
    // cout << socket.getFlags() << endl;   // 1
    // socket = SecureStreamSocket();
    // cout << socket.getFlags() << endl;   // 2
    // return 0;
}

poco中在Socket部分代码中使用的是PIMPL(桥接),Socket类的Impl变量是“桥”,所有的其他派生类通过构造函数的方式将自己的Impl配置给Socket,其UML大概如下:

poco_socket_class.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。