关于多重继承指针回退传递的细节。

引言: 在一个产品中, 看到把一个实现类指针 this, 同时传递给接口Tx, Rx 有感。

当时这个接口没有写好,子类和父类在函数原型定义上一个是const, 一个未定为const, 使得基类传递不给继承类。

这种差别,已经不能称为父子关系了。

接口工作不了,才不得不多看了一眼。并认真的思考了一下问题。

--------------------------------------------------------------------------------

关于多重继承指针回退传递的细节。
1. 问题提出
c 语言时代,有回调函数。 是说传递来一个函数指针,我们来调用这个函数。
这样我们并不关心这个函数的实现,而只是关心这个函数的接口。即它的参数类型,参数个数。

c++时代,进一步表现为。传递过来一个对象指针。我们来调用这个对象的成员函数。
这就是类的回调函数。对于正在写底层逻辑的你来说, 你不关心这个回调对象的实现,而只是
关心它的接口。

c时代,传来的函数可以有不同的地址,从而有不同的表现。
c++时代,这个传来的指针可以是不同的对象。因而也可以有不同的表现形式。但实现这种变化必须要求
各对象具有相同的基类。基类中要求变化的函数声明为虚函数,并且当函数需要不同的表现时,继承类重载基类对应的函数。
看起来,c++一下子比c复杂了不少。
c++实现这种要求的方法是通过建立虚函数表来完成的。
在还不知道未来继承类是怎样实现的情况下, 基础的逻辑控制函数就已经按照基类的要求来完成它的处理流程了。

这里碰到了一种情况。 一个实现类继承了两个虚基类Rx, Tx.
在书写函数时,已经写好了控制流程。 并且这个实现类 implemnet RXTX 也已经完成。
问题是,这个实现类对象,怎样传递给虚基类指针Rx, Tx.
我们知道,子类会退化为父类指针,对应单继承很好理解,对应多重继承, 难道说这个子类即能退化为Tx, 又能退化为Rx吗?
带着这种疑惑, 我研究了这个问题的汇编代码。 得出了结论:

子类在退化为父类指针时,并不是简单的指针赋值,而有可能调整指针位置,这就是c++编译器的强大复杂之处。

2. 研究这个问题的例子。(源码)

#include <stdio.h>
class Tx
{
public:
    virtual void tx_exec() {
        printf("Tx not implement!\n");
    }
private:
    char a;
    char b;
};
class Rx
{
public:
    virtual void rx_exec() {
        printf("Rx not implement!\n");
    }
private:
    int i;
    int j;
};
class RxTx: public Tx, public Rx
{
public:
    void tx_exec() {printf("Tx has implement!\n");}
    void rx_exec() {printf("Rx has implement!\n");}
};

void test(Tx *pTx, Rx *pRx)
{

    printf("pTx:%p\n",pTx);
    printf("pRx:%p\n",pRx);

    pTx->tx_exec();
    pRx->rx_exec();
}
int main()
{
    RxTx obj;

    printf("obj:%p\n",&obj);

    test(&obj, &obj);  // 奥妙就在这里, 前一个&obj, 与后一个&obj 是不同的地址被压栈。
            // 因为obj 包含两个类,前一个地址&obj 指向 Tx 对象部分, 后一个地址&obj 指向 Rx对象部分。
            // Tx对象部分,Rx对象部分第一个参数分别对应各自的虚函数表。从而实现完美退化。
  
    return 0;
}

附上一个结果:

obj:0x7fff78dc7b60
pTx:0x7fff78dc7b60
pRx:0x7fff78dc7b70
Tx has implement!
Rx has implement!


阅读此文,希望你对程序架构一词有更深的理解。 架构就是架子。就是在还没有实现类的时候,就已经用基础类在运转了。

体现"实现"与"接口"的分离。 实际上就是基类和继承类分离。 就是c++ 继承概念。不同的对象表现,就是多态概念。阿弥陀佛!...

 

 

补充: 如果一个实现类需要很多的接口时, 可以采用SendMessage 的结构。 把消息用命令类型来分类。 这样就可以省略很多接口指针。

   MFC 的sendmessage, postmaessage 就是很好的例子。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值