C++学习之继承中的访问控制
我们通常认为一个类有两种不同的用户:普通用户 和 类的实现者。其中,普通用户编写的代码使用类的对象,这部分代码只能访问类的公有(接口)成员;实现者则负责编写类的成员和友元的代码,成员和友元既能访问类的公有部分,也能访问类的私有部分。如果进一步考虑继承的话就会出现第三种用户,即派生类。派生类可以访问基类的公有(public)成员和受保护(protected)成员,但不能访问基类的私有(private)成员。
继承相关点:
- 大多数类都只继承自一个类,这种形式的继承叫做“单继承”。本文主要讲的是单继承。
- 一个派生类的对象中,包含继承自基类的部分和派生类自定义的部分。正因为派生类含有基类部分,所以可以进行派生类到基类的类型转换,这种转换是隐式的。
- 不存在从基类向派生类的隐式类型转换。
- 派生类向基类的自动类型转换只对指针或引用有效,对象之间不存在类型转换。
- 如果基类定义了静态成员,则不论派生出多少个派生类,每个静态成员都只存在唯一实例。
- 防止一个类被继承可以使用关键字final,这时C++11新标准中提供的。
- 继承中的虚函数与纯虚函数(见文章)。
一、公有、私有和受保护成员
1 . 访问说明符
在C++中通过使用访问说明符public、protected、private来对类的成员进行访问控制,控制成员对于普通用户或派生类来说是否可访问:
public:定义为public的成员对普通用户、类的实现者、派生类都是可访问的。public通常用于定义类的外部接口。
protected:定义protected成员的目的是让派生类可以访问而禁止其他用户访问。所以类的实现者和派生类可以访问,而普通用户不能访问。
private:定义为private的成员只能被类的实现者(成员和友元)访问。private部分通常用于封装(即隐藏)类的实现细节。
class People{
protected:
string name;
};
class Student : public People{
public:
friend void Print(Student &s);
friend void Print(People &p);
};
// 正确,可以通过派生类对象访问基类的protected成员
void Print(Student &s){ s.name="Songlee"; cout<< s.name << endl; }
// 错误,不能通过基类对象访问基类的protected成员
void Print(People &p){ p.name="Songlee"; cout<< p.name << endl; }
需要注意的是,派生类的成员或友元只能通过派生类对象来访问基类的受保护成员。派生类对于一个基类对象中的受保护成员没有任何访问特权。
2 . 改变成员的可访问性
有时我们需要改变派生类继承的某个名字的访问级别,通过使用using声明:
class People{
protected:
string name;
};
class Student : public People{
public:
using People::name; // 将继承来的name成员的访问权限改为public
};
int main()
{
Student me;
me.name = "SongLee"; // 可以访问name了
cout << me.name << endl;
return 0;
}
通过在类的内部使用using声明语句,我们可以将该类的直接或间接基类中的任何可访问成员(非私有成员)标记出来,改变其访问权限。
二、公有、私有和受保护继承
我们注意到,在类的派生列表中用到了访问说明符public、protected和private,它们分别表示不同的继承方式:
class A : public B { /* */ }; // 公有继承
class A : private B { /* */ }; // 私有继承
class A : protected B { /* */ }; // 受保护继承
派生类的派生列表中的访问说明符对于派生类的成员(及友元)能否访问其直接基类的成员没什么影响。派生类的成员(及友元)对基类成员的访问权限只与基类中的访问说明符有关。
那么派生列表中的访问说明符有什么作用呢?
派生列表中访问说明符的作用是控制派生类用户对于基类成员的访问权限,注意是派生类的用户。下面给出不同的继承方式导致的访问权限的变化:
public继承:如果继承是公有的,则成员将遵循其原有的访问说明符。父类中的public、protected和private属性在子类中不发生改变。
protected继承:比protected级别高的访问权限会变成protected。即父类中的public属性在子类中变为protected,父类中的protected和private属性在子类中不变。
private继承:比private级别高的访问权限会变成private。即父类中的三种访问属性在子类中都会变成private。
class A { // 基类
public:
string A_public; // 公有成员
protected:
string A_protected; // 受保护成员
};
class B : private A { // 私有继承
public:
B(){ A_public="public"; A_protected="protected"; };
};
int main()
{
B b; // 通过B的对象访问
cout << b.A_public <<" "<< b.A_protected << endl; // 错误,因为是私有继承
return 0;
}
如果我们在派生列表中不使用访问说明符,则struct关键字默认的是公有继承,class关键字默认的是私有继承。不过建议在继承时最好显式地将访问说明符写出来。
另外,不同的继承方式也会影响派生类向基类的转换,假定Derive继承自Base:
只有当Derive公有地继承自Base时,用户代码才能使用派生类向基类的转换;如果Derive继承Base的方式是受保护的或者私有的,则用户代码不能使用该转换。
不论Derive以什么方式继承Base,Derive的成员函数和友元都能使用派生类向基类的转换;派生类向其直接基类的类型转换对于派生类的成员和友元来说永远是可访问的。
如果Derive继承Base的方式是公有的或者受保护的,则Derive的派生类的成员和友元可以使用Derive向Base的类型转换;反之,如果Derive继承Base的方式是私有的,则不能使用。
C++学习之继承中的访问控制的更多相关文章
- java学习笔记-继承中super关键字
背景: 在java继承的概念中我们得知,被声明为私有的类成员对所属的类来说仍然是私有的.类之外的任何代码都不能访问,包括子类. super关键字的两种用法: 1.用于调用超类的构造函数: 2.用于访问 ...
- Java学习之继承中的执行顺序详解
代码块(理解) (1)用{}括起来的代码. (2)分类: A:局部代码块 用于限定变量的生命周期,及早释放,提高内存利用率. B:构造代码块 把多个构造方法中相同的代码可以放到这里,每个构造方法执行前 ...
- C++学习笔记-继承中的构造与析构
C++存在构造函数与析构函数,继承中也存在构造和析构函数.继承中的构造和析构函数与普通的构造析构有细微差别. 赋值兼容性原则 #include "iostream" using n ...
- C++学习之继承中的成员访问控制
由基类到派生类的过程中,在派生类里如何访问基类成员,以及派生类对象如何访问基类成员,是根据派生类在从基类派生时是以什么方式进行的派生:public.protect或者private.下面说一下在这三种 ...
- C++中的类所占内存空间+继承中的成员访问控制
C++学习之继承中的成员访问控制 C++中的类所占内存空间总结
- JavaScript学习13 JavaScript中的继承
JavaScript学习13 JavaScript中的继承 继承第一种方式:对象冒充 <script type="text/javascript"> //继承第一种方式 ...
- Java学习笔记十九:Java中的访问控制修饰符
Java中的访问控制修饰符 一:Java修饰符的种类: 访问修饰符 非访问修饰符 修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class Hello ...
- (C/C++学习)5.C++中的虚继承-虚函数-多态解析
说明:在C++学习的过程中,虚继承-虚函数经常是初学者容易产生误解的两个概念,它们与C++中多态形成的关系,也是很多初学者经常产生困惑的地方,这篇文章将依次分别对三者进行解析,并讲述其之间的联系与不同 ...
- Android(java)学习笔记119:继承中父类没有无参构造
/* 如果父类没有无参构造方法,那么子类的构造方法会出现什么现象呢? 报错. 如何解决呢? A:在父类中加一个无参构造方法 B:通过使用super关键字去显示的调用父类的带参构造方法 C:子类通过th ...
随机推荐
- TCP/IP和UDP的比较
TCP.UDP详解 1.传输层存在的必要性 由于网络层的分组传输是不可靠的,无法了解数据到达终点的时间,无法了解数据未达终点的状态.因此有必要增强网络层提供服务的服务质量. 2.引入传输层的原因 面向 ...
- ArcGIS 坐标系 整理
刚使用ArcGIS的时候,对坐标系的点一直很混乱,今天想要整理整理. 一.地理坐标系与投影坐标系的区分 首先要能区分地理坐标系(GCS)和投影坐标系(PCS). 上面的是地理坐标系的举例,简单理解为不 ...
- Hive DDL&DML
1.删除分区 ALTER TABLE table_name DROP IF EXISTS PARTITION(dt=') 如果是外部表,记得rm对应文件 2.添加分区 ALTER TABLE tabl ...
- (转) 淘淘商城系列——redis-desktop-manager的使用
http://blog.csdn.net/yerenyuan_pku/article/details/72849791 实际工作环境中,redis会安装在服务器上,我们想使用redis服务就要使用re ...
- CAD绘制单行文字(网页版)
在CAD设计时,需要绘制文字,用户可以设置设置绘制文字的高度等属性. 主要用到函数说明: _DMxDrawX::DrawText 绘制一个单行文字.详细说明如下: 参数 说明 DOUBLE dPosX ...
- Java基础——从数组到集合之间关键字的区别!!!!
1.&& 和 &区别和联系: 相同点 : 结果是一样的. 不同点 :如果使用双&号判断,如果说条件一为false,不会判断条件二,但是单&号会继续判 ...
- 数塔(hdoj 2084,动态规划递推)
在讲述DP算法的时候,一个经典的例子就是数塔问题,它是这样描述的: 有如下所示的数塔,要求从顶层走到底层,若每一步只能走到相邻的结点,则经过的结点的数字之和最大是多少? 已经告诉你了,这是个DP的题目 ...
- NOIp2017——追求那些我一直追求的
谨以此祭奠我即将爆炸的NOIP2017. $Mingqi\_H\ \ 2017.09.24$ Day -47 突然发现半年来自己从来没有写对过SPFA,最近几天才发现自己的板子一直是错的...赶紧找个 ...
- Luogu P1311 选择客栈
暴力 我一开始做这道题先想到的就是暴力... 所以先说一下暴力的做法.首先在输入的时候讲花费小于P的位置标记下来,然后用两层循环枚举所有的两个客栈的组合方案.再用一层循环将两个客栈之间的位置扫一遍,如 ...
- docker-compose 报错记录
1.如往常一样对docker-compose.yml配置修改后,docker-compose up -d 后台启动,启动后报错,由原来的done变成了error. 第一反应就是down掉这些容器: d ...