当前位置:C++技术网 > 精选软件 > 关于父子对象相互赋值以及多态特性的分析:1 子类对象赋值给父类对象的理解

关于父子对象相互赋值以及多态特性的分析:1 子类对象赋值给父类对象的理解

更新时间:2017-08-19 14:09:40浏览次数:1+次

    在学习面向对象思想的时候,我们知道有这样一个语法规定:
子类对象可以赋值给父类对象,而父类对象不能赋值给子类对象。父类指针可以接受子类对象地址,并可以在此基础上实现多态特性。
    这段话看似明白,实则大多数人压根就没有搞懂为什么,只是记住了这个规则而已,知道如何使用。那么今天我就这段话来详细分析分析,让大家更好的理解这段话的内在逻辑含义。也就是说,我们这里的分析是会让你真的明白这些规则的含义,而不是加深印象。

1.子类对象赋值给父类对象的理解
    我们先来看一段代码:
#include <cstdio>
class A
{
public:
    void show() { printf("A\n"); }
};
class AA : public A
{
public:
    void show() { printf("ShowAA\n"); }
    void say() { printf("AA\n"); }
};
class BB : public A
{
public:
    void show() { printf("ShowBB\n"); }
    void say() { printf("BB\n"); }
};
int main()
{
    AA aa;
    A a = aa;
    a.show();//A
    aa.show();//ShowAA
    BB bb;
    a = bb;
    a.show();//A
    bb.show();//ShowBB
    //a.say();//错误,A没有成员函数say()
    return 0;
}
    在这一段代码中,我们知道,A是父类(基类),AA和BB是子类(派生类)。AA和BB有一个和A一样的show函数,还有一个额外的say函数。此时,A中的show函数并没有加virtual关键字。所以,AA和BB函数中的show函数并没有构成重载。我们将这种情况称之为覆盖。所以,上述的代码中输出的结果都是自己的类中的show函数的输出。尽管a分别被aa和bb对象赋值,但是a对象的show依然保持本色。
    为什么会这样呢?为了帮助理解,我绘制一个示意图:
    关于父子对象相互赋值以及多态特性的分析1:子类对象赋值给父类对象的理解
    在这个图中,我们绘制了A、AA、BB三个类的内存模型示意图。三个类公共有相同的部分,那就是包含了show函数的部分。AA和BB继承于A,其实也就是克隆了A中的内存结构。所以才表现出来三者在前面一部分的内存是一模一样的。这是继承的基本模型。虽然图形很简单,但是却可以帮助你理解继承。也就是说,我们这份代码中的三个对象,就有这样三块内存块,是相互独立的。
    我们再来理解代码,看看结果是不是好理解了。对象aa赋值给了a,也就是说,用对象aa的数据去填充了a对象。我们这里没有给定成员变量,但是不影响我们理解。不管填充的如何,a还是a,aa还是aa,还是两个相互独立的个体。所以a.show()和aa.show()以及bb.show()就自然而然还是执行对象各自的函数。他们的赋值关系只是改变了被赋值的成员变量的数据而已,我们这里没有定义成员变量,自然也就没有任何影响。所以,以上的结果就顺利成章了。既然相互没有改变,那就还是各自为政。
    然而注释里的a.say()则因为A类中没有say()函数,所以自然就报错了。因为对象的赋值并不会改变对象,所以即使a被aa和bb赋值,a还是a,没有的还是没有。对象赋值只是传递一个数字,并不会给对象新增一个东西。

        很快你会发现,A类中的show函数并没有被定义为virtual,所以AA和BB类并不会重载show函数。按照继承的说法,确实如此。那么如果加上virtual关键字,就可以逆转对象赋值来改变对象吗??不会的!!对象还是对象,不管类如何定义重载,都不能因为对象的赋值而改变了对象的特性的。那么virtual重载又是怎么回事呢???是不是有点懵逼了????我们后面再深入分析。

        总结一下,子类对象赋值给父类对象,是一个冗余信息的交付;而父类对象赋值给子类对象,是一个信息不足的交付。对于信息不足,自然是不允许直接交付的。所以在语法上,子类可以赋值给父类,而父类却不可以赋值给子类。

        更多内容,请看后续的系列文章。。。。