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
- C/C++日常学习总结(第六篇)多基派生引起的虚函数访问二义性问题&重载,覆盖,隐藏的区别
- C/C++日常学习总结(第五篇)多态和虚函数的访问
- 【C++】成员函数的重载,覆盖,隐藏
- C/C++日常学习总结(第十四篇)C++基类与派生类的转换
- c++(成员函数的)重载、覆盖与隐藏
- 函数的多态、重载、覆盖与隐藏(总结)
- C++_重载、重写(覆盖)和隐藏的区别:
- C++【重载,覆盖,隐藏三者的区别】
- C++:成员函数的重载、覆盖与隐藏 、多态
- C++:成员函数的重载、覆盖与隐藏
- C++ 函数重载,覆盖,隐藏,的区别
- C++函数覆盖,重载,隐藏的区别
- 函数重载、覆盖、隐藏的区别
- 函数的重载,覆盖,隐藏区别
- C++成员函数的重载、覆盖、隐藏区别(转载)
- C/C++知识要点3——类成员函数的重载、覆盖和隐藏的区别
- 重载、覆盖、隐藏的区别
- 重载,覆盖,隐藏的区别
- spring 任务调度 Quartz 表达式
- Fzu 2160 Mountain climbing 模拟
- URLClassLoader使用方法和实例
- C中经典的helloworld程序
- open gl 相关网址
- C/C++日常学习总结(第六篇)多基派生引起的虚函数访问二义性问题&重载,覆盖,隐藏的区别
- 将特殊格式的NSSring转换成NSDate
- Device Tree常用方法解析
- 在Android中自定义捕获Application全局异常,可以替换掉系统的强制退出对话框
- android 将图片内容解析成字节数组,将字节数组转换为Ima ...
- Levinux,解决在非linux系统下在linux环境中使用和学习python问题
- Emacs (坑)
- 3DS电游“妖怪手表”销量破百万 7月出售新作
- VC++ 获取文件属性创建时间、修改时间和访问时间