四、同名隐藏,继承的特性——赋值兼容规则

本文深入探讨C++中子类函数同名隐藏与赋值兼容规则,解析子类如何覆盖父类方法及对象切片现象,理解派生类与基类间的转换。

目录

 

一.子类中的函数同名隐藏

二.继承的特性——赋值兼容规则


一.子类中的函数同名隐藏

1.同名隐藏的概念:设在某一继承关系中,子类中有一个和父类中同名的函数 show(),那么子类在调用show()方法时,系统将调用子类的show()方法,而不会去调用父类的show()方法,这种现象叫做同名隐藏。(切记:这里的show()方法不是我后面所说的多态,仅仅称之为同名隐藏)。

例如:

#include<iostream>
using namespace std;

class Base
{
public:
	Base() :x(0)
	{
	}
	~Base()
	{
	}

	void show()
	{
		cout << "这是基类Base的show方法" << endl;
	}
private:
	int x;
};

class D :public Base
{

public:
	D() :y(0)
	{
	}
	~D()
	{
	}

	void print()
	{
		cout << "这是子类D的print方法" << endl;
	}

	void show()
	{
		cout << "这是子类D的show方法" << endl;
	}
private:
	int y;
};
int main()
{
	D d;
	d.print();//访问自己的公有方法
	d.show();/*因为是公有继承,所以子类对象可以访问父类的公有方法show(),
        但是, 当子类也有该方法时 ,将调用子类中的show()方法。 这种现象叫做同名隐藏。 */
	return 0;
}

2.同名隐藏的进一步讨论:如果子类中有和父类中同名的函数,则在子类中将隐藏掉父类中所有的(记住是所有的)
同名函数。
例如,在上面例子中,父类中的show()方法有函数重载:show(int),则在子类中同样会屏蔽掉show(int),
但是,事实上show(int)是被继承下来了,只是被隐藏起来而已。

例如在上述例子中我们给父类中增加show(int)方法:

	void show(int)
	{
		cout<<"这是基类Base的show(int)方法"<<endl; 
	}

如果子类中没有编写show()方法时,子类的对象可以访问父类中的show()和show(int),一旦编写了,则父类中的这两个方法都无法访问,因为发生了同名隐藏

此时我们在主函数中有

int main()
{
	D d;
	d.print();//访问自己的公有方法
	d.show() ;//因为是公有继承,所以子类对象可以访问父类的公有方法show(),但是, 
	          //当子类也有该方法时 ,将调用子类中的show()方法。 这种现象叫做同名隐藏。 
	d.show(0);/*该父类的show(int)方法也被隐藏了,且子类没有自己的show(int)方法,所以这条语句无法执行,是错误的。*/
        return 0;
}

二.继承的特性——赋值兼容规则

1.赋值兼容规则:在任何需要基类对象的地方都可以用公有派生类的对象来代替,这条规则称赋值兼容规则。因为派生类的对象可以赋值给基类的对象,这时是把派生类对象中从对应基类中继承来的隐藏对象赋值给基类对象。反过来不行,基类无法给派生类的新成员赋值。

我们举一个简单的例子来分析以下

#include<iostream>
using namespace std;

class Base
{
public:
	Base() :x(0)
	{
	}
	~Base()
	{
	}
private:
	int x;
};

class Derive:public Base
{
public:
	Derive() :y(0)
	{
	}
	~Derive()
	{
	}
private:
	int y;
};

int main()
{
	 Derive d;
	 Base b;
	 b = d;//尽管类型不同,但是可以直接赋值,不需要借用中间变量,不需要强制转换
	 //d=b;//错误
	return 0;
}

在构造子类对象时,调用父类的构造函数构造了父类的无名对象(隐藏对象),所以,d对象包含两个成员x、y
在用子类对象对父类对象赋值时,将子类对象的中隐藏的父类对象的成员x赋值给了新的父类对象的成员x,形象的称之为
对象的切片。图示。但是反过来,新构造的父类对象只有x成员,但是,子类对象有x和y 成员,故不能用父类对象给子类对象赋值。这种子类对象给基类对象赋值的现象也称之为向上转换。

2.可以将一个派生类的对象的地址赋给其基类的指针变量,但只能通过这个指针访问派生类中由基类继承来的方法,
不能访问派生类中的新成员,这句话非常重要!!!
同样也不能反过来做。

例如:

int main()
{
	Base b;
	Derive d;/*在构造子类对象时,调用父类的构造函数构造了父类的无名对象(隐藏对象),所以,d对象包含两个成员x、y*/ 
	b=d;/*尽管类型不同,但是可以直接赋值,不需要借用中间变量,不需要强制转换*/

	Base *pb;
	pb=&d; //指针类型尽管不同: Base *和  Derive * 
	pb->show(); //pb只能访问父类的show() 方法 
	pb->show(0);//pb只能访问父类的show() 方法 
        //pb->list();//不可访问
	return 0;
 } 
/*假设给子类D增加list()方法,但是pb不能访问list(),所以,pb指针其实只指向了子类对象中隐藏的父类对象。
	void list()
	{
		cout<<"这是子类D的list方法" <<endl;
	}
*/

3.派生类对象可以初始化基类的引用。引用是别名,但这个别名只能包含派生类对象中的由基类继承来的隐藏对象,这句话非常重要!!!

int main()
{
	Base b;
	Derive d;/*在构造子类对象时,调用父类的构造函数构造了父类的无名对象(隐藏对象),所以,d对象包含两个成员x、y*/
	b=d;/*尽管类型不同,但是可以直接赋值,不需要借用中间变量,不需要强制转换 */

	Base *pb;
	pb=&d; //指针类型尽管不同: Base *和  Derive * 
	pb->show(); //pb只能访问父类的show() 方法 
	pb->show(0);//pb只能访问父类的show() 方法 
	//pb->list();/*不可访问*/

	 Base &bf=d; //bf是d的别名,派生类对象可以初始化基类的引用,bf实际上还等同于基类的对象
	 bf.show();
	 bf.show(0);
	 //bf.list();//不能访问 
	return 0;
 } 
/*假设给子类D增加list()方法
	void list()
	{
		cout<<"这是子类D的list方法" <<endl;
	}
*/

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值