C++ 继承方式的调整

在任何继承方式中,除了基类的private成员外,都可以在派生类中分别调整其访问控制。

调整格式

[public: | protected: | private: ] :: ;

class A

{

public:

void f1();

void f2();

void f3();

protected:

void g1();

void g2();

void g3();

}

class B: private A

{

public:

A::f1;//把f1调整为public

A::g1;//把g1调整为public,是否允许弱化基类的访问控制要视具体的实现而定

protected:

A::f2;//把f2调整为protected

A::g2;//把g2调整为protected

}

class C: class B

{

public:

void h()

{

f1(); f2(); g1(); g2();//OK

f3(); g3(); //Error,此时f3,g3是基类B的private成员

}

}

————————————————

C++继承及其特点

继承

继承机制是面向对象程序设计,使代码可以复用最重要手段,它允许在保持原有类的基础上进行扩展,增加功能,这样产生的类,叫做派生类,被派生类继承的类叫做基类。继承呈现了面向对象程序设计的层次结构。体现了由简单到复杂的认知过程。

继承方式

派生类名字: 继承权限:父类的名字

例如:已存在类class A

那么派生类定义为

class Derived: public A

继承权限三种格式

继承的权限跟类中成员的权限一样,有三种权限

public. protected. pritave

默认派生类的继承方式为私有继承方式

如果基类为class,派生类默认继承方式私有

如果基类为struct,派生类默认继承方式为共有

派生类定义方式

//Base //基类 父类

//Derived //派生类 子类

class Base

{

public:

int _b;

};

class Derived : public Base//派生类: 继承方式 基类

{

public:

int _d;

};

继承类型

基类的成员的三种类型,继承到派生类。保护的类型,继承的子类也是保护类型,在类外不可访问。类内可以。非本类不可访问。私有成员在派生类中不可访问。

public(公有方式)

子类Derived继承Base父类的数据。

共有的继承方式,可以访问父类的共有成员与保护成员。但是无法访问私有成员。

基类中public类的 在 子类中也是public

基类中protected类的成员 在 子类中也是 protected

基类中私有成员,仍然归父类私有,虽然子类继承,但是无法访问。但是可以调用父类中共有的方法来访问。

protected(保护方式)

保护的继承方式

基类中:共有的权限 如果是保护的继承方式, 到了子类中,已经从public类改变为protected类。

基类中保护的成员在子类中访问的权限不变。

基类中的私有成员, 子类继承下来了,但是就是用不了。

派生类里可以访问 保护类成员。 类外不行。私有类只能本类中访问。

private(私有方式)

私有的继承方式,基类中所有的成员变量/函数,在派生类中全部变为私有属性。

继承的特点

对象模型: 类中成员变量在内存中的布局形式(非静态成员变量)

class Base

{

public:

int _a;

int _b;

int _c;

};

class Derived : public Base

{

public:

int a;

int b;

int c;

};

以上的基类与派生类在对象存储形式为:

派生类与基类的关系

共有的继承方式,可以将基类对象,当做是派生类对象。

使用角度:所有用到基类的地方,都可以用派生类来代替。

保护的继承方式,protected/private: 子类—基类 相当于has-a的关系

相当于在子类中创建了一个基类对象,基类拥有自己的作用域以及对成员的保护权限。

基类/派生类赋值:切片/切割

子类可以给父类赋值。反过来则不行。(这种方式叫切片/切割)

子类本身就是父类的延伸,因此子类中拥有父类拥有的东西。

派生类给基类赋值时,可以将自己切开,将上半部分的name赋值给基类对象。这种方式叫切片/切割

切片/切割一个天然的行为,并没有伴随着隐式的类型转换,如下证实:

class Base

{

public:

int _a;

int _b;

int _c;

};

class Derived : public Base

{

public:

int a;

int b;

int c;

};

int main()

{

Base B;

Derived D;

B = D;

Base& b = D;

//基类引用对象引用派生类是没有问题的。这个引用变量只能访问到属于基类的数据

//此时没有发生类型转换,引用的是派生类切出来的基类对象,不是类型转换后的数据。

int a = 1;

double d = i;//这里发生隐式类型转换,但是不影响,因为这只是用常量给变量赋值

//double& d1 = i;//因为发生隐式类型转换时,会产生一个临时变量

//此时的double类型的引用变量,引用的是i类型转换后的临时变量的值

//临时变量具有常属性,因此必须将引用类型用const修饰

//与常量的属性保持一致,才可以通过编译。

const double& d1 = i;//此时可以通过编译。

}

基类 = 派生类:

基类访问派生类中基类需要的数据,基类指针可以指向派生类对象。这时的指针可以访问基类的成员。基类的引用,可以引用派生类对象。这是也只是可以访问基类的数据。

派生类 = 基类:

基类对象不能强转为派生类对象,赋值给派生类。赋值时,派生类会访了基类中没有的数据, 会造成越界访问。发生错误。

派生类指针或引用不可以指向或引用基类对象。可能会发生越界访问,所以不允许指向或者引用基类。如果给基类进行强转,将基类引用强转为派生类,强行访问派生类对象,访问到不允许访问的内容,直接出错。除非这个基类对象的指针之前就是指向派生类的指针。

同名隐藏

基类中继承下来的函数,与派生类中的同名函数不能形成重载,而且同名函数还会发生冲突。如果访问相同名称的函数,派生类中只能调用自己类中的函数或者成员。如果想在派生类中访问基类中的同名(成员函数||成员变量)。只能通过加基类类作用域的方式去访问相同名称的基类成员。

d.Base::fun();

同名函数不能形成重载,因为函数重载的条件就是同名函数必须要在同一作用域,尽管基类与派生类函数名相同但参数信息不同, 他们没有在同一个作用域,因此不能形成重载。误当做重载函数调用时,肯定出错。

其实编译器在编译期间会为基类和派生类成员加上对应的作用域限定符,派生类的成员前会加上派生类的作用域限定符,基类的成员会加上基类的作用域限定符。

Base::基类成员 Derived::派生类成员

派生类对象构造函数

派生类对象构造时,先调用派生类构造函数,在派生类构造函数的初始化列表中会调用基类的构造函数,在进入派生类对象的函数体之前,会先在初始化列表中完成派生类中成员的初始化,而这个初始化列表中就有基类的初始化,因此它会先初始化基类中成员(构造基类成员,调用基类的构造函数),之后再初始化派生类的成员。

默认的派生类构造函数只会调用基类的默认构造函数。所以基类的构造函数如果是定义的有参数的,这时必须在派生类的构造函数初始化列表中给出定义。否则构造派生类对象时,找不到默认的基类构造函数,代码不能编译。

派生类的析构函数

(先析构自己的,在最后一个括号处调用基类的析构函数)

如果要销毁派生类的对象,则需要掉用派生类析构函数来清理派生类对象中的资源,在派生类析构函数的最后,需要调用基类的析构函数,以完成基类部分资源的销毁。

final修饰的类

final修饰的类,不能被继承

将类的构造函数定义为私有的, 则变为不可继承的类。(C++11)中 被final修饰的类,不能被继承。

继承与友元函数

友元关系不能继承,基类友元不能访问子类私有和保护成员。因为友元函数不是类的成员,所以不能继承。基类的友元函数因此无法访问派生类的任何成员。

派生类的友元函数,不能访问基类的私有成员,如果是私有的继承方式,那么基类的所有成员都不能访问。就跟派生类的访问权限一致,派生类可以访问到的基类对象,友元函数也能访问到。

静态成员

静态成员变量可以被继承。并且派生类与基类公用这个静态成员。

多继承

多继承方式:

class B1; class B2; //已有的类

class D: public B1,public B2;

B1;

B2;

D;

先继承的基类在上,后继承的基类在下, 派生类在最下。

菱形继承模型:

虚拟继承

虚拟继承

class D: virtual public B//关键字 virtual

1

为了解决菱形继承中的二义性问题,大佬们设计出了虚拟继承。虚拟继承的派生类中,不管派生类中有多少个公用的基类,都公用一个基类。因此在派生类中,前4个字节首先存了一个指针,这个指针指向一个类似数组的区域,里面装着要访问基类对象时,该指针要偏移的偏移量。细节如下:

虚拟继承存储

虚拟继承的派生类,存储方式会先存放派生类对象,将基类对象放在后面存放。

代码表现

#include

using namespace std;

class A

{

public:

int a;

};

class B:virtual public A

{

public:

int b;

};

class C:virtual public A

{

public:

int c;

};

class D:public B, public C

{

public:

int d;

};

int main()

{

D d;

d.B::a = 2;

d.C::a = 1;

d.b = 3;

d.c = 4;

d.d = 5;

cout << sizeof(d) << endl;

}

内存中体现

如果有不对的地方,希望大佬批评。

————————————————

通过分享实用的计算机编程语言干货,推动中国编程到2025年基本实现普及化,使编程变得全民皆知,最终实现中国编程之崛起,这里是中国编程2025,感谢大家的支持。

原文链接:https://blog.csdn.net/haitaolang/article/details/70844494

原文链接:https://blog.csdn.net/qq_41804778/article/details/81561547

在保护继承中基类的共有成员_C++学习大纲:继承方式的调整相关推荐

  1. 在保护继承中基类的共有成员_C++学习刷题13--继承的实现、继承的方式

    一.前言 本部分为C++语言刷题系列中的第13节,主要讲解这几个知识点:继承的实现.继承的方式.欢迎大家提出意见.指出错误或提供更好的题目! 二.知识点讲解 知识点1:继承的实现,可以理解派生类拥有成 ...

  2. 在保护继承中基类的共有成员_C++面向对象:C++ 继承

    面向对象程序设计中最重要的一个概念是继承.继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易.这样做,也达到了重用代码功能和提高执行效率的效果. 当创建一个类时,您不需要重新 ...

  3. 在保护继承中基类的共有成员_c++中的继承

    类的继承,是新的类从已有类那里得到已有的特性.从另一个角度来看这个问题,从已有类产生新类的过程就是类的派生. 派生类的定义 class 派生类名:继承方式 基类名1,继承方式 基类名2 {派生类成员声 ...

  4. 在保护继承中基类的共有成员_C#初学者教程系列11:继承

    本文是C#初学者简单教程,这是第11篇.感谢观看,记得关注我,后续还有更多教程文章,谢谢. 本文环境为Visual Studio 2019. 一.什么是继承 继承是面向对象编程的一种基本特性. 借助继 ...

  5. C++ 类的继承,基类,派生类

    继承: 当创建一个类时,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可. 这个已有的类称为基类,新建的类称为派生类. 例: //基类class Animal {// ...

  6. C++中基类的析构函数为什么要用virtual虚析构函数

    知识背景 要弄明白这个问题,首先要了解下C++中的动态绑定. 关于动态绑定的讲解,请参阅:  C++中的动态类型与动态绑定.虚函数.多态实现 正题 直接的讲,C++中基类采用virtual虚析构函数是 ...

  7. 虚继承c语言例子,C/C++ 多继承{虚基类,虚继承,构造顺序,析构顺序}

    C/C++:一个基类继承和多个基类继承的区别 1.对多个基类继承会出现类之间嵌套时出现的同名问题,如果同名变量或者函数出现不在同一层次,则底层派生隐藏外层比如继承基类的同名变量和函数,不会出现二义性, ...

  8. C++ Primer 5th笔记(chap 15 OOP)继承中的类作用域

    1. 派生类的作用域 每个类定义自己的作用域,作用域内定义成员,当存在继承关系时,派生类的作用域嵌套在其基类的作用域之内.如果一个名字在派生类的作用域内无法正确解析,则编译器将继续在外层的基类作用域中 ...

  9. C++对象内存布局--③测试多继承中派生类的虚函数在哪一张虚函数表中

    C++对象内存布局--③测试多继承中派生类的虚函数在哪一张虚函数表中 测试2:证明派生类的虚函数的地址跟第一基类的虚函数地址保存在同一张虚函数表中. 派生类有多少个拥有虚函数的基类,派生类对象就有多少 ...

最新文章

  1. 性能优化18招提速宝典
  2. linux为什么用tar压缩,linux下tar压缩和解压命令用法详解
  3. 28. 实现strStr()
  4. verilog奇偶分频
  5. python画五子棋棋盘_python 五子棋-文字版(上)
  6. 数据规划(python实现数独自动算法之三)
  7. c语言 %x,%d,%c,%s,%x各代表什么
  8. Paypal联手信用卡Discover 打压Square和星巴克威风
  9. 手机上最简单的计算机,怎么把手机文件传到电脑,才最简单又快速?
  10. Linux 下的 3D 设计软件-FreeCAD
  11. oracle 求时间均值
  12. 关于MBR和GUID分区的问题
  13. 举个栗子!Tableau 技巧(176):快速添加 Server 受信任的 IP
  14. 应用上下文请求上下文
  15. USB Device(VID_1f3a_PID_efe8)
  16. MySQL 的数据备份与恢复
  17. “抄袭事件”开庭小志
  18. 零基础java自学流程-Java语言高级577
  19. Sublime Text Mac完美版
  20. 基于毫米波的远距离手势识别

热门文章

  1. linux终端进程bash,让Linux的进程不受终端影响
  2. vue商城源码_一个标星 5.2k+ 的牛逼开源商城系统
  3. zend studio配置php_PHP-Zend Studio PHP环境的搭建
  4. Sql server时间转时间long
  5. 修改FTP密码的三种方法
  6. 查询同一表内多字段同时重复记录的SQL语句
  7. SPRING CLOUD服务网关之ZUUL
  8. c#中控制不能从一个case标签贯穿到另一个case标签
  9. Javascript实现的2048
  10. BusyBox telnet配置