C++——Inheritence
一种错误的观念:
子类继承父类,只把父类的公有成员继承下来,私有的不会继承。
事实上无论是如何继承,都会把父类的所有成员继承下来。
#include<iostream>
using namespace std; class Base {
private:
int x;
}; class D :private Base{
public:
int y;
}; int main()
{
cout << sizeof(Base) << endl;
cout << sizeof(D) << endl;
return ;
}
输出结果:4 8
继承关系要看2点,见下图

对于继承关键字,我门只需要写一次,但是用的时候却要看2次。见上图2个小人,一个看子类内部通过继承关键字如何看代父类。一个是子类对象通过继承关键字如何看代父类。
不管使用何种继承方式,父类私有数据成员,子类内部都是不能直接访问的。可以通过父类的共有方法间接访问父类私有数据。这里有一点需要注意,假如是private继承父类,父类里面protected数据或方法、public数据或方法、private方法都是可以直接访问的。 这时候如果站在子类内部那个小人的角度看问题,private和protected表现行为差不多。那protected和private区别在哪?
区别在孙子类那里,如果是private继承,Base父类在儿子A那里都是私有的,到了孙子B那里父类无论是数据还是方法都访问不了了。相当于private关键字割断了继承关系,整个继承家族到儿子辈就绝后了。如果是protected就可以保障继承关系不断。
private指定的属性 或 方法,将不能被继承。
protected指定的属性 或 方法,将在类外部不可见,但可以被继承。
派生类的构造函数与析构函数调用顺序

注:图片中 同名覆盖改为同名隐藏
#include<iostream>
using namespace std; class Base1
{
public:
Base1()
{
cout << "Create Base1" << endl;
}
~Base1()
{
cout << "Free Base1" << endl;
}
}; class Base2
{
public:
Base2()
{
cout << "Create Base2" << endl;
}
~Base2()
{
cout << "Free Base2" << endl;
}
}; class Base3
{
public:
Base3()
{
cout << "Create Base3" << endl;
}
~Base3()
{
cout << "Free Base3" << endl;
}
}; class D :public Base2, public Base1, public Base3
{
public:
D()
{
cout << "Create D" << endl;
}
~D()
{
cout << "Free D" << endl;
}
private:
Base1 b1;
Base2 b2;
Base3 b3;
}; int main(int argc, char *argv[])
{
D d;
return ;
}

如果你继承的父类不提供默认或者缺省的构造函数,我们就必须使用参数列表的形式对父类进行构造。参数列表相当于再调用父类的构造函数。
千万不要把参数列表那里的父类构造函数放到子类构造函数里面,那样代表先完成子类构造再完成父类构造。爸爸还没生出来来,怎么会有儿子呢?
#include<iostream>
using namespace std; class Base1
{
public:
Base1(int d=):x(d)
{
cout << "Create Base1" << endl;
}
~Base1()
{
cout << "Free Base1" << endl;
}
private:
int x;
}; class Base2
{
public:
Base2(int d = ):y(d)
{
cout << "Create Base2" << endl;
}
~Base2()
{
cout << "Free Base2" << endl;
}
private:
int y;
}; class Base3
{
public:
Base3(int d = ):z(d)
{
cout << "Create Base3" << endl;
}
~Base3()
{
cout << "Free Base3" << endl;
}
private:
int z;
}; class D :public Base2, public Base1, public Base3
{
public:
D(int data):Base1(data), Base2(data), Base3(data),b1(data), b2(data), b3(data)
{
cout << "Create D" << endl;
}
~D()
{
cout << "Free D" << endl;
}
private:
Base1 b1;
Base2 b2;
Base3 b3;
}; int main(int argc, char *argv[])
{
D d();
return ;
}
参数列表那里的构造函数顺序任意写。决定构造函数顺序只有2处:①继承声明时的顺序②类内部数据成员的顺序。
对于多继承,某一数据成员可能在多个父亲中存在定义。在子类中访问父类数据成员时会存在二义性。下面代码演示,这段代码编译不过
#include<iostream>
using namespace std; class B1
{
public:
B1(int d=):n(d)
{}
~B1()
{}
public:
int n;
}; class B2
{
public:
B2(int d = ):n(d)
{}
~B2()
{}
public:
int n;
}; class D :public B2, public B1
{
public:
D():x()
{}
~D()
{}
private:
int x;
}; int main(int argc, char *argv[])
{
D d;
d.n=;
return ;
}
这种情况需要指明到底是哪个父类的数据成员
#include<iostream>
using namespace std; class B1
{
public:
B1(int d=):n(d)
{}
~B1()
{}
public:
int n;
}; class B2
{
public:
B2(int d = ):n(d)
{}
~B2()
{}
public:
int n;
}; class D :public B2, public B1
{
public:
D():x()
{}
~D()
{}
private:
int x;
}; int main(int argc, char *argv[])
{
D d;
d.B1::n=;
return ;
}
钻石继承
#include<iostream>
using namespace std; class B0
{
public:
B0(int d=):m(d)
{}
~B0()
{}
public:
int m;
}; class B1:public B0
{
public:
B1(int d = ):n(d)
{}
~B1()
{}
public:
int n;
}; class B2 :public B0
{
public:
B2(int d = ) :n(d)
{}
~B2()
{}
public:
int n;
}; class D :public B2, public B1
{
public:
D():x()
{}
~D()
{}
private:
int x;
}; int main(int argc, char *argv[])
{
D d;
d.B1::n=;
d.B1::m = ;
return ;
}


类B1,B2都有m,所以D中要想使用m必须指定具体是哪个类的m
使用virtual关键字,让整个钻石继承使用一个数据成员。这种继承叫虚拟继承
#include<iostream>
using namespace std; class B0
{
public:
B0(int d=):m(d)
{}
~B0()
{}
public:
int m;
}; class B1: virtual public B0
{
public:
B1(int d = ):n(d)
{}
~B1()
{}
public:
int n;
}; class B2 : virtual public B0
{
public:
B2(int d = ) :n(d)
{}
~B2()
{}
public:
int n;
}; class D :public B2, public B1
{
public:
D():x()
{}
~D()
{}
private:
int x;
}; int main(int argc, char *argv[])
{
D d;
d.B1::n=;
d.m = ;
return ;
}

在派生类对象的创建中,首先是虚基类的构造函数并按它们声明的顺序构造。第二批是非虚基类的构造函数按它们声明的顺序调用。第三批是成员对象的构造函数。最后是派生类自己的构造函数被调用
#include<iostream>
using namespace std; class Base1
{
public:
Base1()
{
cout << "Create Base1" << endl;
}
~Base1()
{
cout << "Free Base1" << endl;
}
}; class Base2
{
public:
Base2()
{
cout << "Create Base2" << endl;
}
~Base2()
{
cout << "Free Base2" << endl;
}
}; class Base3
{
public:
Base3()
{
cout << "Create Base3" << endl;
}
~Base3()
{
cout << "Free Base3" << endl;
}
}; class D :public Base2, virtual public Base1, virtual public Base3
{
public:
D()
{
cout << "Create D" << endl;
}
~D()
{
cout << "Free D" << endl;
}
private:
Base1 b1;
Base2 b2;
Base3 b3;
}; int main(int argc, char *argv[])
{
D d;
return ;
}

C++——Inheritence的更多相关文章
- JAVA 1.9 面向对象之封装
1. 面向对象程序设计的三大基本特征:继承(Inheritence).封装(Encapsulation).多态(Polymorphism)2. 封装:类包含了数据与方法,将数据与方法放在一个类中就构成 ...
- Java 编程入门(词汇表)
抽象类(abstract class):抽象类不能创建对象,主要用来创建子类.Java中的抽象类使用 abstract 修饰符定义. 抽象数据类型(abstract data type ADT):抽象 ...
- Java性能提示(全)
http://www.onjava.com/pub/a/onjava/2001/05/30/optimization.htmlComparing the performance of LinkedLi ...
- 常用CSS Reset汇总
什么是Css Reset呢? 在 HTML标签在浏览器里有默认的样式,不同浏览器的默认样式之间也会有差别.在切换页面的时候,浏览器的默认样式往往会给我们带来麻烦,影响开发效率.所以解决的方法就是一开始 ...
- Java SE 第九讲---面向对象特征之封装1
1.面向对象程序设计的三大基本特征:继承(Inheritence).封装(Encapsulation).多态(Polymorphism) 2.封装:类包含数据与方法,将数据与方法放在一个类中就构成了封 ...
- Java SE ---类,方法,对象等
1,面向对象程序设计的三大基本特征:继承(Inheritence).封装(Encapsulation).多态(Polymorphism) 2,如何定义类? 修饰符 cla ...
- 关于Java多态的总结.
[圣思源笔记]JAVA SE Lesson 11. 类是一种抽象的概念,对象是类的一种具体表示形式,是具体的概念.先有类,然后由类来生成对象(Object).对象又叫做实例(Instance).2. ...
- WINAPI 变量(2861个)
WINAPI 变量(2861个) 这是从 c:\Program Files\Windows Kits\8.1\Include\um\WinUser.h 这个文件 中提取的 CTRL+F 查看变量所 ...
- Windows API 常量定义
Windows 常量定义在winuser.h中可以找到,如果了安装了visual studio 2010,winuser.h所在目录为C:\Program Files (x86)\Microsoft ...
随机推荐
- Redis的特性及运用
Redis特性 一个产品的使用场景肯定是需要根据产品的特性,先列举一下Redis的特点: 读写性能优异 持久化 数据类型丰富 单线程 数据自动过期 发布订阅 分布式 这里我们通过几个场景,不同维度说下 ...
- JSON和JSONP具体是干神马的呢? (含jQuery实例)
说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?这两个问题目前都有不同的解决方案,比如数据可以用自定义字符串或者用XML来描述,跨域可以通过服 ...
- 【JQuery】性能优化方法
尽管JavaScript比JAVA C++慢很多,JQuery比原生Js还慢很多,但是我们通过良好的编程习惯还是能提高代码执行的效率. 一.选择器的使用 选择同一个元素,各种方法之间的性能是不一样的, ...
- web端自动化——selenium测试报告生成、找到测试报告路径、实现发邮件(整合)
有这样的一个场景: 假设生成的测试报告与多人相关,每个人都去测试服务器査看就会比较麻烦,如果把这种主动的且不及时的査看变成被动且及时的査收,就方便多了. 整个程序的执行过程可以分为三个步骤: ① ...
- 解决nginx端口占用问题
1.键入命令:netstat -ano | findstr 80 查看80端口被哪个程序占用: 2.键入命令:netsh http show servicestate 查看http服务状态(注:解决后 ...
- [一点感触]ADF4350 ADF4111混频记
几经周折,还是和jack顺利的调完了二者的混频,回想起来我发的上一个版本是2016-11-29,时间可能永远停留在这里了... 祝您一路走好,未来的世界不再忙碌.奔波! 发两张界面纪念吧: 也曾想着把 ...
- 作为注册中心Eureka比Zookeeper好在哪里?
作为注册中心Eureka比Zookeeper好在哪里? 著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性),A(可用性)和P(分区容错性).由于分区容错性P在是分布式系统中必须要保证 ...
- [转帖]oracle补丁类型
oracle补丁类型 https://www.cnblogs.com/liang545621/p/9417919.html 介绍挺好的 跟现在的也比较类似呢. 名称 说明 Release ¤ 标准 ...
- 以php中的算数运算符操作(整型,浮点型,字符串型,布尔型,空类型)数据
// 环境 // // php版本 // PHP 7.0.33-0+deb9u1 (cli) (built: Dec 7 2018 11:36:49) ( NTS ) // Copyright (c) ...
- python 之 re模块、hashlib模块
6.16 re模块 正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法.或者说:正则就是用来描述一类事物的规则.(在Python中)它内嵌在Python中,并通过 ...