跳到主要内容

C++ 50-55 对象模型分析

50 C++对象模型分析(上)

回归本质

  • class是一种特殊的struct

    • 在内存中class依旧可以看作变量的集合
    • class与struct遵循相同的内存对齐规则
    • class中的成员函数与成员变量是分开存放的
      • 每个对象有独立的成员变量
      • 所有对象共享类中的成员函数
  • 值得思考的问题

    class A {
    int i;
    int j;
    char c;
    double d;
    public:
    void print() {
    cout << "i = " << i << ", "
    << "j = " << j << ", "
    << "c = " << c << ", "
    << "d = " << d << endl;
    }
    };

    struct B {
    int i;
    int j;
    char c;
    double d;
    };

    sizeof(A) = ? //20 bytes
    sizeof(B) = ? //20 bytes

编程实验

  • 对象内存布局初探

    #include <iostream>
    #include <string>

    using namespace std;

    class A {
    int i;
    int j;
    char c;
    double d;
    public:
    void print() {
    cout << "i = " << i << ", "
    << "j = " << j << ", "
    << "c = " << c << ", "
    << "d = " << d << endl;
    }
    };

    struct B {
    int i;
    int j;
    char c;
    double d;
    };

    int main() {
    A a;

    cout << "sizeof(A) = " << sizeof(A) << endl; // 20 bytes
    cout << "sizeof(a) = " << sizeof(a) << endl;
    cout << "sizeof(B) = " << sizeof(B) << endl; // 20 bytes

    a.print();

    B* p = reinterpret_cast<B*>(&a);

    p->i = 1;
    p->j = 2;
    p->c = 'c';
    p->d = 3;

    a.print();

    p->i = 100;
    p->j = 200;
    p->c = 'C';
    p->d = 3.14;

    a.print();

    return 0;
    }

C++对象模型分析

  • 运行时的对象退化为结构体的形式
    • 所有成员变量在内存中依次排布
    • 成员变量间可能存在内存空隙
    • 可以通过内存地址直接访问成员变量
    • 访问权限关键字在运行时失效
  • 类中的成员函数位于代码段中
  • 调用成员函数时对象地址作为参数隐式传递
  • 成员函数通过对象地址访问成员变量
  • C++语法规则隐藏了对象地址的传递过程

编程实验

  • 对象本质分析

    //main.cpp
    #include <iostream>
    #include <string>

    using namespace std;

    class Demo {
    int mi;
    int mj;
    public:
    Demo(int i, int j) {
    mi = i;
    mj = j;
    }

    int getI() { return mi;}
    int getJ() { return mj;}
    int add(int value){ return mi + mj + value;}
    };

    int main() {
    Demo d(1, 2);

    cout << "sizeof(d) = " << sizeof(d) << endl;
    cout << "d.getI() = " << d.getI() << endl;
    cout << "d.getJ() = " << d.getJ() << endl;
    cout << "d.add(3) = " << d.add(3) << endl;

    return 0;
    }

    //.h
    #ifndef _50_2_H_
    #define _50_2_H_

    typedef void Demo;

    Demo* Demo_Create(int i, int j);
    int Demo_GetI(Demo* pThis);
    int Demo_GetJ(Demo* pThis);
    int Demo_Add(Demo* pThis, int value);
    void Demo_Free(Demo* pThis);

    #endif
    //.c
    #include "50-2.h"
    #include "malloc.h"

    struct ClassDemo {
    int mi;
    int mj;
    };

    Demo* Demo_Create(int i, int j) {
    struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo));

    if( ret != NULL ) {
    ret->mi = i;
    ret->mj = j;
    }

    return ret;
    }

    int Demo_GetI(Demo* pThis) {
    struct ClassDemo* obj = (struct ClassDemo*)pThis;

    return obj->mi;
    }

    int Demo_GetJ(Demo* pThis) {
    struct ClassDemo* obj = (struct ClassDemo*)pThis;

    return obj->mj;
    }

    int Demo_Add(Demo* pThis, int value) {
    struct ClassDemo* obj = (struct ClassDemo*)pThis;

    return obj->mi + obj->mj + value;
    }

    void Demo_Free(Demo* pThis) {
    free(pThis);
    }
    //main.c
    #include <stdio.h>
    #include "50-2.h"

    int main() {
    Demo* d = Demo_Create(1, 2); // Demo* d = new Demo(1, 2);

    printf("d.mi = %d\n", Demo_GetI(d)); // d->getI();
    printf("d.mj = %d\n", Demo_GetJ(d)); // d->getJ();
    printf("Add(3) = %d\n", Demo_Add(d, 3)); // d->add(3);

    // d->mi = 100;
    Demo_Free(d);

    return 0;
    }

小结

  • C++中的类对象在内存布局上与结构体相同
  • 成员变量和成员函数在内存中分开存放
  • 访问权限关键字在运行时失效
  • 调用成员时对象地址作为参数隐式传递

51 C++对象模型分析(下)

继承对象模型

  • 在C++编译器的内部类可以理解为结构体

  • 子类是由父类成员叠加子类新成员得到的

    class Derived : public Demo {
    int mk;
    };

编程实验

  • 继承对象模型初探

    #include <iostream>
    #include <string>

    using namespace std;

    class Demo {
    protected:
    int mi;
    int mj;
    public:
    virtual void print() {
    cout << "mi = " << mi << ", "
    << "mj = " << mj << endl;
    }
    };

    class Derived : public Demo {
    int mk;
    public:
    Derived(int i, int j, int k) {
    mi = i;
    mj = j;
    mk = k;
    }

    void print() {
    cout << "mi = " << mi << ", "
    << "mj = " << mj << ", "
    << "mk = " << mk << endl;
    }
    };

    struct Test {
    void* p;
    int mi;
    int mj;
    int mk;
    };

    int main() {
    cout << "sizeof(Demo) = " << sizeof(Demo) << endl;
    cout << "sizeof(Derived) = " << sizeof(Derived) << endl;

    Derived d(1, 2, 3);
    Test* p = reinterpret_cast<Test*>(&d);

    cout << "Before changing ..." << endl;

    d.print();

    p->mi = 10;
    p->mj = 20;
    p->mk = 30;

    cout << "After changing ..." << endl;

    d.print();

    return 0;
    }

多态对象模型

  • C++多态的实现原理

    • 当类中声明虚函数时,编译器会在类中生成一个虚函数表
    • 虚函数表是一个存储成员函数地址的数据结构
    • 虚函数表是由编译器自动生成与维护的
    • virtual成员函数会被编译器放入虚函数表中
    • 存在虚函数时,每个对象中都有一个指向虚函数表的指针

编程实验

  • 多态本质分析

    //.h
    #ifndef _51_2_H_
    #define _51_2_H_

    typedef void Demo;
    typedef void Derived;

    Demo* Demo_Create(int i, int j);
    int Demo_GetI(Demo* pThis);
    int Demo_GetJ(Demo* pThis);
    int Demo_Add(Demo* pThis, int value);
    void Demo_Free(Demo* pThis);

    Derived* Derived_Create(int i, int j, int k);
    int Derived_GetK(Derived* pThis);
    int Derived_Add(Derived* pThis, int value);

    #endif
    #include "51-2.h"
    #include "malloc.h"

    static int Demo_Virtual_Add(Demo* pThis, int value);
    static int Derived_Virtual_Add(Demo* pThis, int value);

    struct VTable { // 2. 定义虚函数表数据结构
    int (*pAdd)(void*, int); // 3. 虚函数表里面存储什么???
    };

    struct ClassDemo {
    struct VTable* vptr; // 1. 定义虚函数表指针 ==》 虚函数表指针类型???
    int mi;
    int mj;
    };

    struct ClassDerived {
    struct ClassDemo d;
    int mk;
    };

    static struct VTable g_Demo_vtbl = {
    Demo_Virtual_Add
    };

    static struct VTable g_Derived_vtbl = {
    Derived_Virtual_Add
    };

    Demo* Demo_Create(int i, int j) {
    struct ClassDemo* ret = (struct ClassDemo*)malloc(sizeof(struct ClassDemo));

    if( ret != NULL ) {
    ret->vptr = &g_Demo_vtbl; // 4. 关联对象和虚函数表
    ret->mi = i;
    ret->mj = j;
    }

    return ret;
    }

    int Demo_GetI(Demo* pThis) {
    struct ClassDemo* obj = (struct ClassDemo*)pThis;

    return obj->mi;
    }

    int Demo_GetJ(Demo* pThis) {
    struct ClassDemo* obj = (struct ClassDemo*)pThis;

    return obj->mj;
    }

    // 6. 定义虚函数表中指针所指向的具体函数
    static int Demo_Virtual_Add(Demo* pThis, int value) {
    struct ClassDemo* obj = (struct ClassDemo*)pThis;

    return obj->mi + obj->mj + value;
    }


    // 5. 分析具体的虚函数!!!!
    int Demo_Add(Demo* pThis, int value) {

    struct ClassDemo* obj = (struct ClassDemo*)pThis;

    return obj->vptr->pAdd(pThis, value);
    }

    void Demo_Free(Demo* pThis)
    {
    free(pThis);
    }

    Derived* Derived_Create(int i, int j, int k) {
    struct ClassDerived* ret = (struct ClassDerived*)malloc(sizeof(struct ClassDerived));

    if( ret != NULL ) {
    ret->d.vptr = &g_Derived_vtbl;
    ret->d.mi = i;
    ret->d.mj = j;
    ret->mk = k;
    }

    return ret;
    }

    int Derived_GetK(Derived* pThis) {
    struct ClassDerived* obj = (struct ClassDerived*)pThis;

    return obj->mk;
    }

    static int Derived_Virtual_Add(Demo* pThis, int value) {
    struct ClassDerived* obj = (struct ClassDerived*)pThis;

    return obj->mk + value;
    }

    int Derived_Add(Derived* pThis, int value) {
    struct ClassDerived* obj = (struct ClassDerived*)pThis;

    return obj->d.vptr->pAdd(pThis, value);
    }
    //main.cpp
    #include "stdio.h"
    #include "51-2.h"

    void run(Demo* p, int v) {
    int r = Demo_Add(p, v);

    printf("r = %d\n", r);
    }

    int main() {
    Demo* pb = Demo_Create(1, 2);
    Derived* pd = Derived_Create(1, 22, 333);

    printf("pb->add(3) = %d\n", Demo_Add(pb, 3));
    printf("pd->add(3) = %d\n", Derived_Add(pd, 3));

    run(pb, 3);
    run(pd, 3);

    Demo_Free(pb);
    Demo_Free(pd);

    return 0;
    }

小结

  • 继承的本质就是父子成员变量的叠加
  • C++中的多态是通过虚函数表实现的
  • 虚函数表是由编译器自动生成与维护的
  • 虚函数表的调用效率低于普通成员函数

52 C++中的抽象类和接口

什么是抽象类?

  • 面向对象中的抽象概念 在进行面向对象分析时,会发现一些抽象的概念!图形的面积如何计算?

在现实中需要知道具体的图形类型才能求面积,所以对概念上的“图形”求面积是没有意义的!

class Shape
{
public:
double area()
{
return 0;
}
};

Shape只是一个概念上的类型,没有具体对象!Shape类有必要存在么吗?

  • 面向对象中的抽象类
    • 可用于表示现实世界中的抽象概念
    • 是一种只能定义类型,而不能产生对象的类
    • 只能被继承并且重写相关函数
    • 直接特征是相关函数没有完整的实现
  • Shape是现实世界中各种图形的抽象概念
  • 因此:
    • 程序中必须能够反映抽象的图形
    • 程序中通过抽象类表示图形的概念
    • 抽象类不能创建对象,只能用于继承

抽象类与纯虚函数

  • C++语言中没有抽象类的概念
  • C++中通过纯虚函数实现抽象类
  • 纯虚函数是指只定义原型的成员函数
  • 一个C++类中存在纯虚函数就成为了抽象类
  • 纯虚函数的语法规则
class Shape
{
public:
virtual double area() = 0;
};

“=0”用于告诉编译器当前是声明纯虚函数,因此不需要定义函数体。

编程实验

  • 抽象类初探
#include <iostream>
#include <string>

using namespace std;

class Shape
{
public:
virtual double area() = 0;
};

class Rect : public Shape
{
int ma;
int mb;
public:
Rect(int a, int b)
{
ma = a;
mb = b;
}
double area()
{
return ma * mb;
}
};

class Circle : public Shape
{
int mr;
public:
Circle(int r)
{
mr = r;
}
double area()
{
return 3.14 * mr * mr;
}
};

void area(Shape* p)
{
double r = p->area();

cout << "r = " << r << endl;
}

int main()
{
Rect rect(1, 2);
Circle circle(10);

area(&rect);
area(&circle);

return 0;
}

  • 抽象类只能用作父类被继承
  • 子类必须实现纯虚函数的具体功能
  • 纯虚函数被实现后成为虚函数
  • 如果子类没有实现纯虚函数,则子类成为抽象类
  • 满足下面条件的C++类则称为接口
    • 类中没有定义任何的成员变量
    • 所有的成员函数都是公有的
    • 所有的成员函数都是纯虚函数
    • 接口是一种特殊的抽象类

编程实验

  • 接口初探
#include <iostream>
#include <string>

using namespace std;

class Channel
{
public:
virtual bool open() = 0;
virtual void close() = 0;
virtual bool send(char* buf, int len) = 0;
virtual int receive(char* buf, int len) = 0;
};

int main()
{
return 0;
}

小结

  • 抽象类用于描述现实世界中的抽象概念
  • 抽象类只能被继承不能创建对象
  • C++中没有抽象类的概念
  • C++中通过纯虚函数实现抽象类
  • 类中只存在纯虚函数的称为接口
  • 接口是一种特殊的抽象类

53 被遗弃的多重继承(上)

问题

C++中是否允许一个类继承自多个父类?

C++中的多重继承

  • C++支持编写多重继承的代码
    • 一个子类可以拥有多个父类
    • 子类拥有所有父类的成员变量
    • 子类继承所有父类的成员函数
    • 子类对象可以当作任意父类对象使用
  • 多重继承的语法规则
class Derived : public BaseA,public BaseB,public BaseC
{
//......
};

多重继承的本质与单继承相同!

编程实验

  • 多重继承问题一
#include <iostream>
#include <string>

using namespace std;

class BaseA
{
int ma;
public:
BaseA(int a)
{
ma = a;
}
int getA()
{
return ma;
}
};

class BaseB
{
int mb;
public:
BaseB(int b)
{
mb = b;
}
int getB()
{
return mb;
}
};

class Derived : public BaseA, public BaseB
{
int mc;
public:
Derived(int a, int b, int c) : BaseA(a), BaseB(b)
{
mc = c;
}
int getC()
{
return mc;
}
void print()
{
cout << "ma = " << getA() << ", "
<< "mb = " << getB() << ", "
<< "mc = " << mc << endl;
}
};

int main()
{
cout << "sizeof(Derived) = " << sizeof(Derived) << endl; // 12

Derived d(1, 2, 3);

d.print();

cout << "d.getA() = " << d.getA() << endl;
cout << "d.getB() = " << d.getB() << endl;
cout << "d.getC() = " << d.getC() << endl;

cout << endl;

BaseA* pa = &d;
BaseB* pb = &d;

cout << "pa->getA() = " << pa->getA() << endl;
cout << "pb->getB() = " << pb->getB() << endl;

cout << endl;

void* paa = pa;
void* pbb = pb;


if( paa == pbb )
{
cout << "Pointer to the same object!" << endl;
}
else
{
cout << "Error" << endl;
}

cout << "pa = " << pa << endl;
cout << "pb = " << pb << endl;
cout << "paa = " << paa << endl;
cout << "pbb = " << pbb << endl;

return 0;
}

多重继承的问题一

通过多重继承得到的对象可能拥有“不同的地址”! 解决方案:无

Derived d(1,2,3);
BaseA *pa = &d;
BaseB *pb = &d

多重继承的问题二

  • 多重继承可能产生冗余的成员

编程实验

  • 多重继承问题二
#include <iostream>
#include <string>

using namespace std;

class People
{
string m_name;
int m_age;
public:
People(string name, int age)
{
m_name = name;
m_age = age;
}
void print()
{
cout << "Name = " << m_name << ", "
<< "Age = " << m_age << endl;
}
};

class Teacher : virtual public People
{
public:
Teacher(string name, int age) : People(name, age)
{
}
};

class Student : virtual public People
{
public:
Student(string name, int age) : People(name, age)
{
}
};

class Doctor : public Teacher, public Student
{
public:
Doctor(string name, int age) : Teacher(name, age), Student(name, age), People(name, age)
{
}
};

int main()
{
Doctor d("Delphi", 33);

d.print();

return 0;
}

当多重继承关系出现闭合时将产生数据冗余的问题! 解决方案:虚继承

class Peploe{ };
class Teacher : virtual public People{ };
class Student : virtual public People{ };
class Doctor : public Teacher,public Student{ };
  • 虚继承能够解决数据冗余问题
  • 中间层父类不再关心顶层父类的初始化
  • 最终子类必须直接调用顶层父类的构造函数

问题:当架构设计中需要继承时,无法确定使用直接继承还是虚继承!

小结

  • C++支持多重继承的编程方式
  • 多重继承容易带来问题
    • 可能出现“同一个对象的地址不同”的情况
    • 虚继承可以解决数据冗余的问题
    • 虚继承使得架构设计可能出现问题

54 被遗弃的多重继承(下)

多重继承的问题三

  • 多重继承可能产生多个虚函数表

编程实验

  • 多重继承问题三
#include <iostream>
#include <string>

using namespace std;

class BaseA
{
public:
virtual void funcA()
{
cout << "BaseA::funcA()" << endl;
}
};

class BaseB
{
public:
virtual void funcB()
{
cout << "BaseB::funcB()" << endl;
}
};

class Derived : public BaseA, public BaseB
{

};

int main()
{
Derived d;
BaseA* pa = &d;
BaseB* pb = &d;
BaseB* pbe = (BaseB*)pa; // oops!!
BaseB* pbc = dynamic_cast<BaseB*>(pa);

cout << "sizeof(d) = " << sizeof(d) << endl;

cout << "Using pa to call funcA()..." << endl;

pa->funcA();

cout << "Using pb to call funcB()..." << endl;

pb->funcB();

cout << "Using pbc to call funcB()..." << endl;

pbc->funcB();

cout << endl;

cout << "pa = " << pa << endl;
cout << "pb = " << pb << endl;
cout << "pbe = " << pbe << endl;
cout << "pbc = " << pbc << endl;

return 0;
}

需要进行强制类型转换时,C++中推荐使用新式类型转换关键字! 解决方案:dynamic_cast

Derived d;
BaseA *pa = &d;
BaseB *pb = &d;
BaseB *pbb = (BaseB*)pa;

正确的使用多重继承

  • 工程开发中的“多重继承”方式:单继承某个类+实现(多个)接口

编程实验

  • 正确的多继承方式
#include <iostream>
#include <string>

using namespace std;

class Base
{
protected:
int mi;
public:
Base(int i)
{
mi = i;
}
int getI()
{
return mi;
}
bool equal(Base* obj)
{
return (this == obj);
}
};

class Interface1
{
public:
virtual void add(int i) = 0;
virtual void minus(int i) = 0;
};

class Interface2
{
public:
virtual void multiply(int i) = 0;
virtual void divide(int i) = 0;
};

class Derived : public Base, public Interface1, public Interface2
{
public:
Derived(int i) : Base(i)
{
}
void add(int i)
{
mi += i;
}
void minus(int i)
{
mi -= i;
}
void multiply(int i)
{
mi *= i;
}
void divide(int i)
{
if( i != 0 )
{
mi /= i;
}
}
};

int main()
{
Derived d(100);
Derived* p = &d;
Interface1* pInt1 = &d;
Interface2* pInt2 = &d;

cout << "p->getI() = " << p->getI() << endl; // 100

pInt1->add(10);
pInt2->divide(11);
pInt1->minus(5);
pInt2->multiply(8);

cout << "p->getI() = " << p->getI() << endl; // 40

cout << endl;

cout << "pInt1 == p : " << p->equal(dynamic_cast<Base*>(pInt1)) << endl;
cout << "pInt2 == p : " << p->equal(dynamic_cast<Base*>(pInt2)) << endl;

return 0;
}

  • 一些有用的工程建议
    • 先继承自一个父类,然后实现多个接口
    • 父类中提供equal()成员函数
    • equal()成员函数用于判断指针是否指向当前对象
    • 与多重继承相关的强制类型转换用dynamic_cast完成

小结

  • 多继承可能出现多个虚函数表指针
  • 与多重继承相关的强制类型转换用dynamic_cast完成
  • 工程开发中采用"单继承多接口"的方式使用多继承
  • 父类提供成员函数用于判断指针是否指向当前对象

55 经典问题解析四

关于动态内存分配

new和malloc的区别是什么?

delete和free的区别是什么?

  • new关键字与malloc函数的区别
    • new关键字是C++的一部分
    • malloc是由C库提供的函数
    • new以具体类型为单位进行内存分配
    • malloc以字节为单位进行内存分配
    • new在申请内存空间时可进行初始化
    • malloc仅根据需要申请定量的内存空间
  • 下面的代码输出什么?为什么?
class Test
{
public:
Test
{
cout<<"Test"<<endl;
}
};
int main()
{
Test *pn = new Test;
Test *pm = (Test*)malloc(sizeof(Test)); //不自动执行构造函数,只分配空间
return 0;
}

编程实验

  • new和malloc的区别
#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

class Test
{
int* mp;
public:
Test()
{
cout << "Test::Test()" << endl;

mp = new int(100);

cout << *mp << endl;
}
~Test()
{
delete mp;

cout << "~Test::Test()" << endl;
}
};

int main()
{
Test* pn = new Test;
Test* pm = (Test*)malloc(sizeof(Test));

delete pn;
free(pm);

return 0;
}
  • new和malloc的区别
    • new在所有C++编译器中都被支持
    • malloc在某些系统开发中是不能调用
    • new能够触发构造函数的调用
    • malloc仅分配需要的内存空间
    • 对象的创建只能使用new
    • malloc不适合面向对象开发
  • 下面的代码输出什么?为什么?
int main()
{
Test *pn = new Test;
Test *pm = (Test*)malloc(sizeof(Test));
delete pn;
free(pm); //只释放堆空间,不自动调用析构函数
return 0;
}
  • delete和free的区别
    • delete在所有C++编译器中都被支持
    • free在某些系统开发中是不能调用
    • delete能够触发析构函数的调用
    • free仅归还之前分配的内存空间
    • 对象的销毁只能使用delete
    • free不适合面向对象开发

关于虚函数

构造函数是否可以成为虚函数?

析构函数是否可以成为虚函数?

  • 构造函数不可能成为虚函数
    • 在构造函数执行结束后,虚函数表指针才会被正确的初始化
  • 析构函数可以成为虚函数
    • 建议在设计类时将析构函数声明为虚函数

编程实验

  • 构造,析构,虚函数
#include <iostream>
#include <string>

using namespace std;

class Base
{
public:
Base()
{
cout << "Base()" << endl;

func();
}

virtual void func()
{
cout << "Base::func()" << endl;
}

virtual ~Base()
{
func();

cout << "~Base()" << endl;
}
};


class Derived : public Base
{
public:
Derived()
{
cout << "Derived()" << endl;

func();
}

virtual void func()
{
cout << "Derived::func()" << endl;
}

~Derived()
{
func();

cout << "~Derived()" << endl;
}
};


int main()
{
Base* p = new Derived();

// ...

delete p;

return 0;
}

构造函数中是否可以发生多态?

析构函数中是否可以发生多态?

  • 构造函数中不可能发生多态行为
    • 在构造函数执行时,虚函数表指针未被正确初始化
  • 析构函数中不可能发生多态行为
    • 在析构函数执行时,虚函数表指针已经被销毁

构造函数和析构函数中不能发生多态行为,只调用当前类中定义的版本!

关于继承中的强制类型转换

继承中如何正确的使用强制类型转换?

  • dynamic_cast是与继承相关的类型转换关键字
  • dynamic_cast要求相关的类中必须有虚函数
  • 用于有直接或者间接继承关系的指针(引用)之间
    • 指针:
      • 转换成功:得到目标类型的指针
      • 转换失败:得到一个空指针
    • 引用:
      • 转换成功:得到目标类型的引用
      • 转换失败:得到一个异常操作信息
  • 编译器会检查dynamic_cast的使用是否正确
  • 类型转换的结果只可能在运行阶段才能得到

编程实验

  • dynamic_cast的使用
#include <iostream>
#include <string>

using namespace std;

class Base
{
public:
Base()
{
cout << "Base::Base()" << endl;
}

virtual ~Base()
{
cout << "Base::~Base()" << endl;
}
};

class Derived : public Base
{

};

int main()
{
Base* p = new Base;

Derived* pd = dynamic_cast<Derived*>(p);

if( pd != NULL )
{
cout << "pd = " << pd << endl;
}
else
{
cout << "Cast error!" << endl;
}

delete p;

return 0;
}

小结

  • new/delete会触发构造函数或者析构函数的调用
  • 构造函数不能成为虚函数
  • 析构函数可以成为虚函数
  • 构造函数和析构函数都无法产生多态行为
  • dynamic_cast是与继承相关的专用转换关键字