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

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_data
		cout<<"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 C
	pA->b();		//b()在A, B类中都是虚函数, C类中没有定义, 编译器无法确定使用哪个
					//版本, 只能采用静态联编. 由于pA的类型是A *,所以输出: b() in A
	pA->c();		//c()在A中为虚函数, B中为普通函数, C中进行了重定义. 此时输出取决
					//于指针pA的类型A, 由于c()在A中为虚函数, 故按照虚函数的规则处理,输出c() in C

	cout << endl;

	B* pB = &c;		//用派生类对象obc的地址为B类指针赋值
	pB->a();		//a()在A, B , C三个类中都是虚函数, 调用C类的c(), 输出: a() in C
	pB->b();		//b()在A, B类中都是虚函数, C类中没有定义, 编译器无法确定使用哪个
					//版本, 只能采用静态联编. 由于pB的类型是B *,所以输出: b() in B
	pB->c();		//c()在A中为虚函数, B中为普通函数, C中进行了重定义. 此时输出取决
					//于指针pB的类型B, 由于c()在B中为普通函数, 故按照普通函数的规则处理,输出c() in B
	pB->d();		//d()在B, C类中都定义为普通函数, C中的d()会隐藏基类B中的d(), 但pB类型为B *, 故输出d() in B

	cout << 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 C
	pC->d();		//d()在B, C类中都定义为普通函数, C中的d()会隐藏基类B中的d(), 但pC类型为C *, 故输出d() in C

	return 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关键字,基类中的同名函数即被屏蔽(区别重载:范围不同)

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值