C++的三种继承方式(本文先不涉及虚继承)

题外话,关于基类的protected成员(虽然是题外话,但是这个点对于讲继承很重要)

在总结这三种继承方式之前,要先澄清两个误区。

一、类的访问权限修饰,是类级别的,也就是class level的,而不是对象级别的。同一个类的两个不同的对象,是可以互相访问对方的保护成员和私有成员的。

二、好多人对下面这句话都曾经有过一个错误的认识。

“对于基类的protected成员,派生类的成员函数和友元函数具有访问权限。”(这是一句不应该说的话,因为表达出来的意思很容易让人产生误解)

这句话说的比较模糊,完整清楚的表达应该是:“派生类的成员函数和友元函数,可以访问派生类对象中的基类部分的protected成员(和public成员)。但是,对于独立的基类对象中的protected成员,派生类是没有访问权限的,除非又把派生类声明为基类的友元类。” 
为了理解上面这一段话,请考虑下面这个例子。

class Base{
public:
	void pub_mem();
protected:
	int prot_mem;
private:
	char priv_mem;
};

class Derived : public Base{
public:
	int visitBaseObj(Base&);
	int visitBaseObj_1();
}

int Derived::visitBaseObj(Base& Bobj){
	return ( Bobj.prot_mem );		//错误,不能通过基类对象直接访问Base的protected成员
}
int Derived::visitBaseObj_1(){
	return prot_mem;			//正确,派生类的成员函数和友元函数,可以访问派生类的基类部分的protected成员
}

题外话说完,回到正题。


C++的继承有三种方式,public继承、protected继承和private继承。
提到继承,就肯定会提到基类和派生类,注意,我们这里说的基类都是默认指的直接基类,如果用到间接基类,会显式强调指出的。

  1. 这三种继承不论是哪种继承,基类的private在派生类的基类部分,还是基类部分的private,这个private对子类都是拒绝访问的。
  2. 对于public继承:就是把基类的public变成了派生类中带有基类域属性的public,把基类的protected变成了派生类中带有基类域属性的protected;
  3. 对于protected继承:就是把基类的public和protected变成了派生类中带有基类域属性的protected,注意这个protect的所有权是属于派生类的;
  4. 对于private继承:就是把基类的public和protected变成了派生类中带有基类域属性的private,注意这个private的所有权是属于派生类的。
  5. 类的对象只能访问本类中的public成员,类中的成员函数和友元可以访问类中(除了基类部分的private成员)的所有成员。
简单可依赖。


下面展开来细讲一下。

总的来说,某个类对其继承而来的成员的访问权限受到两个因素的影响:一是在基类中该成员的访问说明符;二是在派生类的派生列表中的访问说明符。
值得注意的是,对于派生类中的成员函数和友元函数能否访问  派生类的基类部分的成员,派生列表中的访问说明符  是不会产生什么影响的。

派生类中的成员函数和友元函数,对派生类的基类部分的成员的访问权限,只与基类中的访问说明符有关。举个例子:

class Base{
public:
	void pub_mem();
protected:
	int prot_mem;
private:
	char priv_mem;
};

struct Pub_Derv : public Base{
	//f()函数正确,派生类可以访问 派生类的基类部分 的protected成员
	int f() {	return prot_mem;	}
	//g()函数错误,派生类不可以访问 派生类的基类部分 的private成员
	char g() {	return priv_mem;	}
};
//对于派生类的成员函数和友元函数 的访问权限,private和protected继承对其不产生任何影响(但是一会儿要讲,会影响派生类对象的访问权限)
struct Priv_Derv : private Base{
	//f()函数正确,派生类可以访问 派生类的基类部分 的protected成员
	int f() {	return prot_mem;	}
	//g()函数错误,派生类不可以访问 派生类的基类部分 的private成员
	char g() {	return priv_mem;	}
};

看到这里,我们知道了 派生列表中的访问说明符,对于 派生类中的成员函数和友元函数能否访问  派生类的基类部分的成员,不会产生任何影响。


那么派生列表中的访问说明符,有什么作用呢?有两点作用。

  • 第一点作用:派生访问说明符,是用于控制派生类用户(包括派生类的派生类在内),对于派生类的基类部分的成员的访问权限。  派生类用户,说白了就是指由派生类生成的对象。类的对象只能调用本类中的public成员。

接着上面的例子,

Pub_Derv pub_obj;
Priv_Derv priv_obj;

pub_obj.pub_mem();		//正确,派生类对象可以访问派生类的基类部分的public成员
pub_obj.prot_mem;		//错误,对象只可以访问本类的public成员

priv_obj.pub_mem();		//错误,派生类对象不可以访问派生类的基类部分的原先的public成员,因为此时pub_mem()在派生类中是private的

  • 第二点作用:派生类访问说明符还可以控制继承自派生类的新类的访问权限。
对于private继承,则在Priv_Derv类中,继承自Base的所有成员都是私有的,但这个私有是有区别的。Base基类以前的private现在仍是派生类中基类部分自己私有的,但是Base基类以前的public和protected现在是派生类私有的,是可以被派生类的成员函数和友元所访问的。

如果是protected继承,则在Prot_Derv类中,继承自Base的所有public和protected成员都是protected的,而Base中原有的private成员仍是派生类的基类部分自己private的。

所以可以看到:

  • private继承截断了继承的访问通道,下一个孙子派生类将无法访问爷爷基类的public和protected成员,同时关闭了派生类对象直接访问基类public成员的通道。
  • protected继承则依旧保持了继承访问通道的畅通,但同时也关闭了派生类对象直接访问基类public成员的通道。

私有继承和保护继承,建立的是has-a关系。所以这两种继承又被称为继承实现,但不继承接口。因为派生类对象不能显式地使用基类的接口。因此,不能将派生类对象看做是一种基类对象。也正是 由于这个原因,在不进行显式转换的情况下,基类指针或引用将不能指向派生类对象


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值