【C++学习笔记】父类指针指向子类对象
? ? ? ? 虚函数的作用主要是实现了多态的机制。简而言之就是用父类型的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。但仅仅可调用父类含有的函数,非父类函数不能调用。 普通虚函数调用假设我们有下面的类层次: #include using namespace std; class A { public: ?? ?A(){}; ?? ?~A(){} ?? ?virtual void foo() ?? ?{ ?? ??? ?cout << "A::foo() is called" << endl; ?? ?} }; class B :public A { public: ?? ?B(){} ?? ?~B(){} ?? ?void foo() ?? ?{ ?? ??? ?cout << "B::foo() is called" << endl; ?? ?} ?? ?void fun() ?? ?{ ?? ??? ?cout << "B::fun() is called" << endl; ?? ?} ?? ?virtual void fun1() ?? ?{ ?? ??? ?cout << "B::fun() is called" << endl; ?? ?} }; int main(void) { ?? ?A *a = new B(); ?? ?a->foo(); ? ? // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的! ?? ?// a->fun(); ?// 这里调用错误,提示:error C2039: “fun”: 不是“A”的成员,?e:debugbasetestmain.cpp(8) : 参见“A”的声明 ?? ?// a->fun1(); // 这里调用错误,提示:error C2039: “fun1”: 不是“A”的成员,?e:debugbasetestmain.cpp(8) : 参见“A”的声明 ?? ?return 0; } 以上例子说明,子类的虚函数替换了父类的同名虚函数(参见【C++学习笔记】虚函数实现多态原理)实现通过父类调用子类函数实现的功能。非父类含有的函数无法调用。 构造函数与析构函数调用假设有如下类层次: class A { public: ?? ?A(){ cout << "A::A() is called" << endl; }; ?? ?~A(){ cout << "A::~A() is called" << endl; } ?? ?virtual void foo() ?? ?{ ?? ??? ?cout << "A::foo() is called" << endl; ?? ?} }; class B :public A { public: ?? ?B(){ cout << "B::B() is called" << endl; } ?? ?~B(){ cout << "B::~B() is called" << endl; } ?? ?void foo() ?? ?{ ?? ??? ?cout << "B::foo() is called" << endl; ?? ?} }; int main(void) { ?? ?A *a = new B(); ?? ?a->foo(); ? ? // 在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的! ?? ?delete a; ?? ?return 0; } 程序输出: A::A() is called B::B() is called B::foo() is called A::~A() is called 由程序输出可以看出,程序先构造父类,再构造子类,析构时由于父类的析构函数非虚函数,所以未调用子类的析构函数。若子类的构造函数存在动态内存分配,则会存在内存泄漏的问题。若父类析构函数为虚函数,则程序输出如下: A::A() is called B::B() is called B::foo() is called B::~B() is called A::~A() is called 子类的动态内存分配就可以被释放。 父子类指针强制转换的安全性假设有如使用: int main(void) { ?? ?A *a = new A(); ?? ?B *b = static_cast(a); ?? ?b->fun();? ?? ?delete b; ?? ?return 0; } 程序输出: A::A() is called B::foo() is called A::~A() is called 父类指针强制转换为子类指针,并调用了子类函数,释放时释放的是父类A指针,并未释放B指针。父类指针a强制转换过程中并未调用子类B构造函数,释放时也未调用子类B析构函数。说明父类向下强制转换存在较大风险,如下所示: class A { public: ?? ?A(){ cout << "A::A() is called" << endl; }; ?? ?virtual~A(){ cout << "A::~A() is called" << endl; } ?? ?virtual void foo() ?? ?{ ?? ??? ?cout << "A::foo() is called" << endl; ?? ?} }; class B :public A { public: ?? ?B() ?? ?{? ?? ??? ?cout << "B::B() is called" << endl;? ?? ??? ?pt = new int[10]; ?? ??? ?for (int i = 0; i < 10; i++) ?? ??? ??? ?pt[i] = i; ?? ?} ?? ?virtual~B() ?? ?{? ?? ??? ?cout << "B::~B() is called" << endl;? ?? ??? ?delete [] pt; ?? ?} ?? ?void foo() ?? ?{ ?? ??? ?cout << "B::foo() is called" << endl; ?? ?} ?? ?void fun() ?? ?{ ?? ??? ?cout << "B::fun() is called" << endl; ?? ??? ?cout << pt[0] << endl; ?? ?} ?? ?int *pt; }; int main(void) { ?? ?A *a = new A(); ?? ?B *b = static_cast(a); ?? ?b->fun();? ?? ?delete a; ?? ?return 0; } 程序输出异常,因为子类B调用的函数使用了需要在子类构造函数中动态分配的内存。因为强制转换过程中,未调用子类B的构造函数。 int main(void) { ?? ?A *a = new B(); ?? ?B *b = static_cast(a); ?? ?b->fun();? ?? ?delete a; ?? ?return 0; } 程序输出: A::A() is called B::B() is called B::fun() is called B::~B() is called A::~A() is called 父类指针强制转换为子类指针,并调用了子类函数,释放时释放的是父类A指针,并释放B指针。此情况说明:父类指针a指向子类指针,再将父类指针转换为子类B使用的安全的。可能因为父类指针a指向的内存块包含构造子类B的所有空间。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |