• C++基类和派生类指针的相互赋值和转换

    在公有派生的情况下,派生类的指针可以直接赋值给基类指针。但即便基类指针指向的是一个派生类的对象,也不能通过基类指针访问基类没有而派生类中有的成员。

    基类的指针不能赋值给派生类的指针。但是通过强制类型转换,也可以将基类指针强制转换成派生类指针后再赋值给派生类指针。只是在这种情况下,程序员需要保证被转换的基类指针本来就指向一个派生类的对象,这样才是安全的,否则很容易出错。

    下面的代码演示了基类和派生类指针的互相转换:

    #include <iostream>
    using namespace std;
    class CBase
    {
    protected:
        int n;
    public:
        CBase(int i) :n(i) { }
        void Print() { cout << "CBase:n=" << n << endl; }
    };
    class CDerived :public CBase
    {
    public:
        int v;
        CDerived(int i) :CBase(i), v(2 * i) { }
        void Func() { };
        void Print()
        {
            cout << "CDerived:n=" << n << endl;
            cout << "CDerived:v=" << v << endl;
        }
    };
    int main()
    {
        CDerived objDerived(3);
        CBase objBase(5);
        CBase * pBase = &objDerived; // 使得基类指针指向派生类对象
                                     //pBase->Func(); //错, CBase类没有Func()成员函数
                                     //pBase->v = 5;  //错 CBase类没有v成员变量
        pBase->Print();
        cout << "1)------------" << endl;
        //CDerived * pDerived = & objBase; //错,不能将基类指针赋值给派生类指针
        CDerived * pDerived = (CDerived *)(&objBase);
        pDerived->Print();  //慎用,可能出现不可预期的错误
        cout << "2)------------" << endl;
        objDerived.Print();
        cout << "3)------------" << endl;
        pDerived->v = 128;  //往别人的空间里写入数据,会有问题
        objDerived.Print();
        return 0;
    }

    在 Dev C++ 4.9.9.2 下的运行结果:
    CBase:n=3
    1)------------
    CDerived:n=5
    CDerived:v=5
    2)------------
    CDerived:n=3
    CDerived:v=6
    3)------------
    CDerived:n=128
    CDerived:v=6

    第 27 行使得基类指针 pBase 指向派生类对象 objDerived,这是合法的。执行完此行后,虽然 pBase 指向的是派生类对象,但是第 28 行如果不注释掉,编译是会出错的,因为 CBase 类并没有 Func 成员函数。

    同理,第 29 行若不注释掉也会出错。

    第 30 行,尽管基类和派生类都有 Print 成员函数,而且 pBase 指向的是派生类对象,本行执行的依然是基类的 Print 成员函数,产生第一行输出。

    总之,编译器看到的是哪个类的指针,那么就会认为要通过它访问哪个类的成员,编译器不会分析基类指针指向的到底是基类对象还是派生类对象。

    第 33 行,通过强制类型转换,使得派生类的指针 pDerived 指向了基类对象 objBase。第 34 行调用的 Print 成员函数就是 CDerived 类的 Print 成员函数。

    这是有风险的语句。在 CDerived 对象中,成员变量 v 紧挨成员变量 n 存放,如图 1 所示。


    图1:派生类对象的内存空间

更多...

加载中...