C/C++日常学习总结(第六篇)多基派生引起的虚函数访问二义性问题&重载,覆盖,隐藏的区别

来源:互联网 发布:中华大字典软件 编辑:程序博客网 时间:2024/05/18 12:32

1.构造函数和析构函数的调用顺序析构函数为什么要虚拟?

//析构函数调用不当带来的内存泄漏#include <iostream>using namespace std;class Base//基类定义{private://字符指针char* data;public:Base()//无参构造函数{data = new char[64];                //动态内存申请cout<<"Base类构造函数被调用"<<endl;};
        <span style="color:#cc0000;">virtual</span> ~Base()        //析构函数{delete [] data;        //data指向的内存被释放cout<<"Base类析构函数被调用"<<endl;};};class Child : public Base               //Child类由基类Base派生而来{private:char* m_data;       //增添的字符指针成员public:Child():Base()       //构造函数,初始化表中执行基类的构造函数{m_data = new char[64];               //动态申请内存,并将首地址赋给m_datacout<<"Child类构造函数被调用"<<endl;};~Child()       //析构函数{delete [] m_data;       //内存资源释放cout<<"Child类析构函数被调用"<<endl;};};int main(){Base *pB = new Child;               //动态申请了一块Child大小的内存,赋给Base基类指针delete pB;       //基类析构函数执行return 0;}

【解析】:

// Base类构造函数被调用

// Child类构造函数被调用

// Base类析造函数被调用

//Child类的析构函数没有被执行。(如果没加virtual)

这是因为上述代码的析构函数是非虚的,//释放时会造成child类的析构函数得不到执行,从而导致内存泄漏//解决方法:将Base类的析构函数申明为虚函数即可. 即在 ~Base() 前面加上 virtual

2.多基派生引起的虚函数访问二义性问题

#include <iostream>using namespace std;class A{public:virtual void a() //虚函数{cout << "a() in A" << endl;}virtual void b() //虚函数{cout << "b() in A" << endl;}virtual void c() //虚函数{cout << "c() in A" << endl;}};class B{public:virtual void a() //虚函数{cout << "a() in B" << endl;}virtual void b() //虚函数{cout << "b() in B" << endl;}void c()         //非虚函数{cout << "c() in B" << endl;}void d()         //非虚函数{cout << "d() in B" << endl;}};class C:public A, public B{public:virtual void a() //虚函数,覆盖{cout << "a() in C" << endl;}void c()         //特殊{cout << "c() in C" << endl;}void d()         //非虚函数,隐藏{cout << "d() in C" << endl;}};int main(){C c;//声明一个派生类对象c//c.b();//b()在A, B类中都定义为虚函数, C中无法确定使用哪个版本, 引起二义性错误cout << "c.b();会引起二义性错误" << endl;cout << endl;A* pA = &c;//用派生类对象obc的地址为A类指针赋值pA->a();//a()在A, B , C三个类中都是虚函数, 调用C类的c(), 输出: a() in CpA->b();//b()在A, B类中都是虚函数, C类中没有定义, 编译器无法确定使用哪个//版本, 只能采用静态联编. 由于pA的类型是A *,所以输出: b() in ApA->c();//c()在A中为虚函数, B中为普通函数, C中进行了重定义. 此时输出取决//于指针pA的类型A, 由于c()在A中为虚函数, 故按照虚函数的规则处理,输出c() in Ccout << endl;B* pB = &c;//用派生类对象obc的地址为B类指针赋值pB->a();//a()在A, B , C三个类中都是虚函数, 调用C类的c(), 输出: a() in CpB->b();//b()在A, B类中都是虚函数, C类中没有定义, 编译器无法确定使用哪个//版本, 只能采用静态联编. 由于pB的类型是B *,所以输出: b() in BpB->c();//c()在A中为虚函数, B中为普通函数, C中进行了重定义. 此时输出取决//于指针pB的类型B, 由于c()在B中为普通函数, 故按照普通函数的规则处理,输出c() in BpB->d();//d()在B, C类中都定义为普通函数, C中的d()会隐藏基类B中的d(), 但pB类型为B *, 故输出d() in Bcout << endl;C *pC = &c;pC->a();//a()在A, B , C三个类中都是虚函数, 调用C类的c(), 输出: a() in C//pC->b();//b()在A, B类中都定义为虚函数, C中无法确定使用哪个版本, 引起二义性错误cout << "pC->b();会引起二义性错误" << endl;pC->c();//c()在A中为虚函数, B中为普通函数, C中进行了重定义(?). 此时输出取决//于指针pC的类型C, c()在C中无论是虚函数还是普通函数, 都输出c() in CpC->d();//d()在B, C类中都定义为普通函数, C中的d()会隐藏基类B中的d(), 但pC类型为C *, 故输出d() in Creturn 0;}

【解析】:

       前面在学习继承时也存在二义性,单基派生的二义性,多基继承的二义性,上面代码中产生的二义性,跟多基继承产生的二义性处理方式一致,//引起二义性错误. 解决: pC->B::b();

3.重载,覆盖,隐藏的区别

(1.)成员函数被重载的特征:

class A{……virtual int fun();void fun(int);void fun(double,double);……};

1).相同的范围(同一个类中)

2).函数名相同

3).参数不同(参数个数·参数类型)

4).virtual关键字可有可无

 

(2.)覆盖是指派生类函数覆盖基类函数,特征是:

class A{public:virtual void fun1(int, int) {}virtual int  fun2(char *){return 0;}};class B : public A{public:void fun1(int, int){}};class C : public B{public:int fun2(char *) {return 1;}};
//B中的fun1覆盖了A中的fun1,同时继承了A中的fun2//C类继承了B中的fun1,同时重定义覆盖了fun2

1).不同的范围(基类和派生类)

2).函数名相同

3).参数相同,返回类型相同

4).基类函数中必须有virtual关键字

(3.)隐藏,指派生类中的函数屏蔽了与其同名的基类中函数,特征:

class A//类A的定义{public:void fun(int xp)//非虚成员函数fun,参数为int型{cout << xp << endl;}};class B:public A//类B由类A派生而来{public:void fun(char* s)//隐藏,oversee,参数为字符串{cout << s << endl;}};

 

1).函数名相同,参数也相同,但是没有virtual关键字(区别覆盖:virtual有无)

2).函数名相同,但参数不同,不论有无virtual关键字,基类中的同名函数即被屏蔽(区别重载:范围不同)

 

0 0
原创粉丝点击