我们通常认为一个类有两种不同的用户:普通用户类的实现者。其中,普通用户编写的代码使用类的对象,这部分代码只能访问类的公有(接口)成员;实现者则负责编写类的成员和友元的代码,成员和友元既能访问类的公有部分,也能访问类的私有部分。如果进一步考虑继承的话就会出现第三种用户,即派生类。派生类可以访问基类的公有(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++学习之继承中的访问控制的更多相关文章

  1. java学习笔记-继承中super关键字

    背景: 在java继承的概念中我们得知,被声明为私有的类成员对所属的类来说仍然是私有的.类之外的任何代码都不能访问,包括子类. super关键字的两种用法: 1.用于调用超类的构造函数: 2.用于访问 ...

  2. Java学习之继承中的执行顺序详解

    代码块(理解) (1)用{}括起来的代码. (2)分类: A:局部代码块 用于限定变量的生命周期,及早释放,提高内存利用率. B:构造代码块 把多个构造方法中相同的代码可以放到这里,每个构造方法执行前 ...

  3. C++学习笔记-继承中的构造与析构

    C++存在构造函数与析构函数,继承中也存在构造和析构函数.继承中的构造和析构函数与普通的构造析构有细微差别. 赋值兼容性原则 #include "iostream" using n ...

  4. C++学习之继承中的成员访问控制

    由基类到派生类的过程中,在派生类里如何访问基类成员,以及派生类对象如何访问基类成员,是根据派生类在从基类派生时是以什么方式进行的派生:public.protect或者private.下面说一下在这三种 ...

  5. C++中的类所占内存空间+继承中的成员访问控制

    C++学习之继承中的成员访问控制 C++中的类所占内存空间总结

  6. JavaScript学习13 JavaScript中的继承

    JavaScript学习13 JavaScript中的继承 继承第一种方式:对象冒充 <script type="text/javascript"> //继承第一种方式 ...

  7. Java学习笔记十九:Java中的访问控制修饰符

    Java中的访问控制修饰符 一:Java修饰符的种类: 访问修饰符 非访问修饰符 修饰符用来定义类.方法或者变量,通常放在语句的最前端.我们通过下面的例子来说明: public class Hello ...

  8. (C/C++学习)5.C++中的虚继承-虚函数-多态解析

    说明:在C++学习的过程中,虚继承-虚函数经常是初学者容易产生误解的两个概念,它们与C++中多态形成的关系,也是很多初学者经常产生困惑的地方,这篇文章将依次分别对三者进行解析,并讲述其之间的联系与不同 ...

  9. Android(java)学习笔记119:继承中父类没有无参构造

    /* 如果父类没有无参构造方法,那么子类的构造方法会出现什么现象呢? 报错. 如何解决呢? A:在父类中加一个无参构造方法 B:通过使用super关键字去显示的调用父类的带参构造方法 C:子类通过th ...

随机推荐

  1. Java编程思想读书笔记_第7章

    final关键字类似const: import java.util.*; public class FinalData { static Random rand = new Random(47); f ...

  2. 转载--Beautifuisoup的使用

    转载自--http://mp.weixin.qq.com/s?src=11&timestamp=1520511185&ver=742&signature=KDzYoOg8Xd9 ...

  3. 【转】jvm类加载

    类加载机制 JVM把class文件加载的内存,并对数据进行校验.转换解析和初始化,最终形成JVM可以直接使用的Java类型的过程就是加载机制. 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命 ...

  4. python行与缩进

    #python行与缩进 1.了解逻辑行与物理行 2.行中分号使用规则 3.行链接 4.什么是缩进 5.如何缩进 6.注释 1.python中逻辑行主要是指一段代码,在意义上它的行数,而物理行,指的是我 ...

  5. 如何利用CSS中的ime-mode用来控制页面上文本框中的全角/半角输入

    css 之 ime-mode语法:ime-mode : auto | active | inactive | disabled取值:auto : 默认值.不影响ime的状态.与不指定 ime-mode ...

  6. TF实战:(Mask R-CNN原理介绍与代码实现)-Chapter-8

    二值掩膜输出依据种类预测分支(Faster R-CNN部分)预测结果:当前RoI的物体种类为i第i个二值掩膜输出就是该RoI的损失Lmask 对于预测的二值掩膜输出,我们对每个像素点应用sigmoid ...

  7. JS的filter用法

    filter也是一个常用的操作,它用于把Array的某些元素过滤掉,然后返回剩下的元素. 和map()类似,Array的filter()也接收一个函数.和map()不同的是,filter()把传入的函 ...

  8. ansible结合playbook批量部署war包项目上线

    批量部署jenkins.war包实现上线 用于测试war包上线 [root~localhost]~#vim /etc/ansible/test.yml - hosts: test vars:     ...

  9. Leetcode 498:对角线遍历Diagonal Traverse(python3、java)

    对角线遍历 给定一个含有 M x N 个元素的矩阵(M 行,N 列),请以对角线遍历的顺序返回这个矩阵中的所有元素,对角线遍历如下图所示. Given a matrix of M x N elemen ...

  10. 搜索--P1101 单词方阵

    题目描述 给一n×n的字母方阵,内可能蕴含多个"yizhong"单词.单词在方阵中是沿着同一方向连续摆放的.摆放可沿着 8 个方向的任一方向,同一单词摆放时不再改变方向,单词与单词 ...