【C++入门】访问权限管控和继承机制详解

1、C++的三种权限管控

class A
{
public:
	//成员变量和函数,在类的其他成员函数和类的对象可以直接访问

private:
	//成员变量和函数,在类的其他成员函数中可以直接访问,但是不可以通过类的对象直接访问,在派生类中不可以直接访问

protected:
	//成员变量和函数,在类的其他成员函数中可以直接访问,但是不可以通过类的对象直接访问,在派生类中可以直接访问
};

2、C++为什么要设计访问权限

(1)保护内部资源。比如:private的成员是class内部使用,外部没必要访问或者说不想外部能直接访问,于是语法上就将需要保护的资源权限定义为private,于是外部便不能直接访问;
(2)隐藏外部无需关心的细节。比如:外部能直接访问的就是public权限的变量和函数,至于public的成员方法去访问private和protected权限的变量和函数,外部便不需要感知;
(3)隐藏class中不需要外部关注的细节,可以降低使用class类的难度;
(4)隐藏不需要外部关注的细节,也可以防止外部不小心去修改;
(5)访问权限是语法层面的保护,是编译器在编译链接时帮我们检查权限,而不是硬件内存上存在这些权限;

3、设计类时如何规定成员的访问权限

(1)需要被外界访问的成员直接设置为public
(2)只能在当前类中访问的成员设置为private
(3)只能在当前类和子类中访问的成员设置为protected。

4、C语言中的"继承"

//基类
struct A
{
	int a;
}

//派生类
struct B
{
	struct A;	//继承struct A
	int b;
}

(1)首先C语言没有继承这个机制和概念,但是实际代码中却有类似继承的用法;
(2)上面的struct A可以看做是基类,struct B是派生类继承了struct A,这种用法和C++的继承思想是一样的;

5、C++中的继承

5.1、继承特性的语法

class 派生类名:访问控制 基类名1,访问控制 基类名2,访问控制 基类名n
{
	// 成员变量和成员方法列表(除了构造和析构之外的成员方法)
};

(1)新构建类时,可以同时继承多个基类,基类之间以逗号分隔;
(2)访问控制:指明继承的方式,分为public(共有)继承、private(私有)继承、protected(保护)继承;

5.2、继承的概念

(1)继承是C++源生支持的一种语法特性,是C++面向对象的一种表现;
(2)继承特性可以让派生类“瞬间”拥有基类的所有(当然还得考虑权限)属性和方法;
(3)继承特性本质上是为了代码复用;

5.3、派生类和基类的关系

(1)派生类,表示范围小,更具体;基类,表示范围大,更抽象。比如:人这个概念范围就很大,男人和女人表示的范围比人就要小一些,男人和女人的概念更具体,但是男人和女人都属于人,所以男人和女人这两个类都可以去集成人这个基类;
(2)派生类和基类是从属关系,可以描述为:派生类是基类的一种。比如:男人是人的一种,而不能说人是男人的一种;
(3)派生类集成基类只是为了借助基类快速定义派生类,派生类定义好后,派生类的对象访问的都是派生类自己的成员变量和成员函数,和基类已经没有关系了;

5.4、三种继承的结果

基类成员继承后的权限
基类的public经过public继承,在子类中是public;经过private继承,在子类中是private;经过protected继承,在子类中是protected;
基类的private不管何种继承方式,基类的private成员在派生类中都是一种比private管控更严格的权限。换句话说,就是派生类是不能直接访问基类的private成员的;
基类的protected经过public继承,在子类中是protected;经过private继承,在子类中是private;经过protected继承,在子类中是protected;

5.5、为什么基类的private成员,在派生类中不能直接访问?

(1)首先派生类是继承了基类的所有成员,包括基类的private成员;
(2)private成员表示这些成员是类私有的,不希望外部能访问。
(3)基类的private成员,表示这些成员是基类私有的,外部不能访问;虽然派生类继承了基类,但是派生类并不是基类,如果派生类也能直接访问基类的private成员,那就打破了private的定义;
(4)派生类只是不能直接访问基类的private成员,但是可以通过基类提供的public、protected权限的成员去间接访问;

6、三种继承方式的示例代码

6.1、public继承

#include <iostream>
#include <string>

using namespace std;

//person类表示所有人共有的特性
class person
{
public:
	int gender;	//性别,0代表男,1代表女
	void getName(void);

	//构造函数
	person(){};
	person(string myName, int myGender, int myAge):name(myName),gender(myGender),age(myAge){}

private:
	string name;

protected:
	int age;

};

void person::getName(void)
{
	cout << "person::getName name=" << this->name << endl;
}

//adult类表示成年人
class adult:public person
{
public:
	void work(void);	//成年人多增加工作的特性

	//构造函数
	adult(){};
	adult(string myname, int myGender, int myAge);

	void print(void);
	
private:

protected:
	

};

//adult类的构造函数
adult::adult(string myname, int myGender, int myAge):person(myname, myGender, myAge)
{

}

void adult::work(void)
{
	cout << "man::work" << endl;
}

void adult::print(void)
{
	//cout << "man::name=" << this->name << endl;
	cout << "man::gender=" << this->gender << endl;
	cout << "man::age=" << this->age << endl;
}

int main(void)
{
	adult ad("linux", 1, 23);

	ad.getName();
	ad.print();
	
	//cout << "ad.name=" << ad.name << endl;
	cout << "ad.gender=" << ad.gender << endl;
	//cout << "ad.age=" << ad.age << endl;
	
	return 0;
} 

6.2、private继承

#include <iostream>
#include <string>

using namespace std;

//person类表示所有人共有的特性
class person
{
public:
	int gender;	//性别,0代表男,1代表女
	void getName(void);

	//构造函数
	person(){};
	person(string myName, int myGender, int myAge):name(myName),gender(myGender),age(myAge){}

private:
	string name;

protected:
	int age;

};

void person::getName(void)
{
	cout << "person::getName name=" << this->name << endl;
}

//adult类表示成年人
class adult:private person
{
public:
	void work(void);	//成年人多增加工作的特性

	//构造函数
	adult(){};
	adult(string myname, int myGender, int myAge);

	void print(void);
	
private:

protected:
	

};

//adult类的构造函数
adult::adult(string myname, int myGender, int myAge):person(myname, myGender, myAge)
{

}

void adult::work(void)
{
	cout << "man::work" << endl;
}

void adult::print(void)
{
	//cout << "man::name=" << this->name << endl;
	cout << "man::gender=" << this->gender << endl;
	cout << "man::age=" << this->age << endl;
}

int main(void)
{
	adult ad("linux", 1, 23);

	//ad.getName();
	ad.print();
	
	//cout << "ad.name=" << ad.name << endl;
	//cout << "ad.gender=" << ad.gender << endl;
	//cout << "ad.age=" << ad.age << endl;
	
	return 0;
} 

6.3、protected继承

#include <iostream>
#include <string>

using namespace std;

//person类表示所有人共有的特性
class person
{
public:
	int gender;	//性别,0代表男,1代表女
	void getName(void);

	//构造函数
	person(){};
	person(string myName, int myGender, int myAge):name(myName),gender(myGender),age(myAge){}

private:
	string name;

protected:
	int age;

};

void person::getName(void)
{
	cout << "person::getName name=" << this->name << endl;
}

//adult类表示成年人
class adult:protected person
{
public:
	void work(void);	//成年人多增加工作的特性

	//构造函数
	adult(){};
	adult(string myname, int myGender, int myAge);

	void print(void);
	
private:

protected:
	

};

//adult类的构造函数
adult::adult(string myname, int myGender, int myAge):person(myname, myGender, myAge)
{

}

void adult::work(void)
{
	cout << "man::work" << endl;
}

void adult::print(void)
{
	//cout << "man::name=" << this->name << endl;
	cout << "man::gender=" << this->gender << endl;
	cout << "man::age=" << this->age << endl;
}

int main(void)
{
	adult ad("linux", 1, 23);

	//ad.getName();
	ad.print();
	
	//cout << "ad.name=" << ad.name << endl;
	//cout << "ad.gender=" << ad.gender << endl;
	//cout << "ad.age=" << ad.age << endl;
	
	return 0;
} 

6.4、示例代码分析

(1)屏蔽起来的代码就是表示不能访问的,否则就会报错,和三种继承的权限结合起来看;
(2)可以将权限的严格程序做个排序:private > protected > public;
(3)继承时候确认基类成员在派生类中的权限,可以理解成:比较该成员在基类中的权限和继承权限,选择最高的那个权限作为基类成员在派生类中的权限;

7、不良继承

7.1、何为不良继承

(1)鸵鸟不是鸟的问题:鸟作为基类提供了fly的方法,鸵鸟属于鸟,所以去集成了鸟这个基类,但是鸵鸟并不会fly,从基类继承的fly这个方法对鸵鸟来说就是很多余的;
(2)不良继承是客观存在的。比如上面的"鸵鸟不是鸟"的问题,你不把鸵鸟划分成鸟不恰当,你把鸵鸟划分为鸟也不太恰当,毕竟鸵鸟除了不会飞其他都是满足鸟的特性;

7.2、解决办法

(1)消除继承关系:既然鸵鸟继承鸟会出现不会fly这种不良继承,那就尝试找一个更贴近的基类去继承;
(2)弱化基类:将鸟这个基类中fly成员去掉,各种鸟去继承基类时,根据自己的情况决定是否添加fly这个成员;
总结:两种方式没有高低之分,根据实际情况来采用;

8、派生类和基类的构造/析构函数关系

参考博客:《【C++入门】派生类和基类的构造/析构函数关系》

9、派生类和基类的同名成员问题

(1)在派生类和基类中存在同名的成员时,派生类的对象调用的是派生类实现的成员,此时基类的成员被隐藏,也叫重定义
(2)但是在派生类还是可以调用基类的同名成员的,可以使用指定域名的方法:父类::成员;显示的指定要调用父类的成员而不是派生类的成员;

10、派生类和基类的类型兼容规则

10.1、派生类和基类的关系

(1)C++语言是强类型语言,每个变量都是有类型的,如果类型不匹配编译就会报错;
(2)派生类是基类的超集:派生类继承基类,所以基类有的派生类全都有,而派生类独有的基类则没有;
(3)派生类的对象可以裁剪后当基类使用,而基类的对象则不能放大当派生类使用,否则可能会出错;
总结:派生类对象可以当基类的对象使用,反之则不行;

10.2、类型兼容规则

(1)子类对象可以当作父类对象使用,也就是说子类对象可以无条件隐式类型转换为一个父类对象
(2)子类对象可以直接初始化或直接赋值给父类对象
(3)父类指针可以直接指向子类对象
(4)父类引用可以直接引用子类对象

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

正在起飞的蜗牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值