C++中的继承(1) 继承方式
1、继承与派生
继承是使代码可以复用的重要手段,也是面向对象程序设计的核心思想之一。简单的说,继承是指一个对象直接使用另一对象的属性和方法。继承呈现了 面向对象程序设 计的层次结构, 体现了 由简单到复杂的认知过程。C++中的继承关系就好比现实生活中的父子关系,继承一笔财产比白手起家要容易得多,原始类称为基类,继承类称为派生类,它们是类似于父亲和儿子的关系,所以也分别叫父类和子类。而子类又可以当成父类,被另外的类继承。继承的方式有三种分别为公有继承(public),保护继承(protect),私有继承(private)。
定义格式如下:
2、继承方式及访问属性
(1) 公有继承(public)
公有继承的特点是基类的公有成员和保护成员作为派生类的成员时,它们都保持原有的状态,而基类的私有成员对派生类是不可见的,也不能被这个派生类的子类所访问。
(2)私有继承(private)
私有继承的特点是基类的公有成员和保护成员都作为派生类的私有成员,并且不能被这个派生类的子类所访问。
(3)保护继承(protected)
保护继承的特点是基类的所有公有成员和保护成员都成为派生类的保护成员,并且只能被它的派生类成员函数或友元访问,基类的私有成员仍然私有,且对派生类不可见。
private能够对外部和子类保密,即除了成员所在的类本身可以访问之外,别的都不能直接访问。protected能够对外部保密,但允许子类直接访问这些成员。public、private和protected对成员数据或成员函数的保护程度可以用下表来描述:
举个栗子:
class Base //父类
{
private:
int _priB;
protected:
int _proB;
public:
int _pubB;
} ;
class Derived: public Base //子类,继承自base,继承类型为公有继承
{
private:
int _d_pri;
protected:
int _d_pro;
public:
void funct()
{
int d;
d=_priB; //error:基类中私有成员在派生类中是不可见的
d=_proB; //ok: 基类的保护成员在派生类中为保护成员
d=_pubB; //ok: 基类的公共成员在派生类中为公共成员
}
int _d_pub;
} ;
总结:(1). public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用, 因为每个子类对象也都是一个父类对象。
class C :private Base //基类Base的派生类C(私有继承)
{
public:
void funct()
{
int c;
c=_priB; //error:基类中私有成员在派生类中是不可见的
c=_proB; //ok:基类的保护成员在派生类中为私有成员
c=_pubB; //ok:基类的公共成员在派生类中为私有成员
}
};
class E :protected Base //基类Base的派生类E(保护继承)
{
public:
void funct()
{
int e ;
e=_priB; //error:基类中私有成员在派生类中是不可见的
e=_proB; //ok:基类的保护成员在派生类中为保护成员
e=_pubB; //ok:基类的公共成员在派生类中为保护成员
}
};
总结:
(2). 基类的private成员 在派生类中是不能被访问的, 如果基类成员 不想在类外直接被访问, 但需要 在派生类中能访问, 就定义为protected。 可以看出保护成员 限定符是因继承才出现的。
(3). protected/private继承是一个实现继承, 基类的部分成员 并非完全成为子类接口 的一部分, 是 has-a 的关系原则, 所以非特殊情况下不会使用这两种继承关系, 在绝大多数的场景下使用的 都是公有继承。 私有继承以为这is-implemented-in-terms-of(是根据……实现的) 。 通常比组合(composition) 更低级, 但当一个派生类需要访问 基类保护成员 或需要重定义基类的虚函数时它就是合理的。
int main()
{
int a;
D d;
a=D._priB; //error:公有继承基类中私有成员在派生类中是不可见的,对对象不可见
a=D._proB; //error:公有继承基类的保护成员在派生类中为保护成员,对对象不可见
a=D._pubB; //ok:公有继承基类的公共成员在派生类中为公共成员,对对象可见
C c;
a=c._priB; //error:私有继承基类中私有成员在派生类中是不可见的, 对对象不可见
a=c._proB; //error:私有继承基类的保护成员在派生类中为私有成员,对对象不可见
a=c._pubB; //error:私有继承基类的公共成员在派生类中为私有成员,对对象不可见
E e;
a=e._priB; //error:保护继承基类中私有成员在派生类中是不可见的, 对对象不可见
a=e._proB; //error:保护继承基类的保护成员在派生类中为保护成员,对对象不可见
a=e._pubB; //error:保护继承基类的公共成员在派生类中为保护成员,对对象不可见 return ;
}
(4)不管是哪种继承方式, 在派生类内部都可以访问基类的公有成员和保护成员 , 基类的私有成员存在但是在子类中不可见( 不能访问) 。
(5)使用关键字class时默认的继承方式是private, 使用struct时默认的继承方式是public, 不过最好显式的写出继承方式。
(6)在实际运用中一般使用都是public继承, 极少场景下才会使用protetced/private继承。
在struct继承中,如果没有显式给出继承类型,则默认的为public继承;在class继承中,如果没有显式给出继承类型,则默认的为private继承;
继承关系&访问限定符
注意:派生类需要添加自己的构造函数(下一篇会详细分析这些特性)
(1)创建派生类对象时,程序首先创建基类对象;
(2)要通过初始化表用基类的构造函数给继承过来的成员变量提供初始值;
(3)如果省略了基类的初始化表,程序会使用基类的默认构造函数;
(4)也应初始化派生类新增的数据成员;
(5)派生类对象过期时,首先调用派生类的析构,再调用基类的析构;
(6)派生类应根据需要添加自己的成员变量和方法;
3、基类与派生类的关系-指针或引用
(1)基类指针或引用可以在不进行显式类型转换的情况下指向或引用派生类对象,但是基类指针或引用只能调用基类的方法,无法调用派生类的方法,而派生类指针或引用是不能指向或引用基类对象的;
(2)参数为基类引用或指针的函数,也可以将派生类对象作为参数,这可以让基类对象使用派生类来初始化;
(3)这也可以将派生类赋值给基类 – 此时派生类的基类部分被复制给基类,将派生类对象赋值给基类对象,但这只涉及到基类的部分,派生类中的派生部分将被忽略掉,其实质是调用基类的赋值运算符 – 此函数参数为基类的引用;
(4)公有继承建立一种is-a 关系 – is-a-kind-of
即派生类是基类的一种 – 只是比基类更特殊了一下而已,并非 is-like-a – 即没有比喻关系,派生类只能在基类的基础上添加属性,但是不能删除属性,并非 is-implenmented-as-a – 即没有实现关系 如数组可以用来实现栈,但是不能从Array派生出Stack类,而是将数组对象封装在栈里并非use-a – 即没有使用关系 – 可以通过友元或类来实现类之间的通信(使用)。public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。比如白马是马,香蕉是水果。
(5)protetced/private继承建立一种has-a 关系
C++中的继承(1) 继承方式的更多相关文章
- JS中5种经典继承方式
继承 JS中继承的概念: 通过[某种方式]让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承 并不是所谓的xxx extends yyy 为什么要使用继承? 有些对象会有方法(动作 ...
- C++中的三种继承方式
1,被忽略的细节: 1,冒号( :)表示继承关系,Parent 表示被继承的类,public 的意义是什么? class Parent { }; class Child : public Parent ...
- js中的原型、继承的一些想法
最近看到一个别人写的js类库,突然对js中的原型及继承产生了一些想法,之前也看过其中的一些内容,但是总不是很清晰,这几天利用空闲时间,对这块理解了一下,感觉还是有不通之处,思路上没那么条理,仅作为分享 ...
- JavaScript是如何实现继承的(六种方式)
大多OO语言都支持两种继承方式: 接口继承和实现继承 ,而ECMAScript中无法实现接口继承,ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现,下文给大家技术js实现继承的 ...
- 详解js中的寄生组合式继承
寄生组合式继承是js中最理想的继承方式, 最大限度的节省了内存空间. js中的寄生组合式继承要求是: 1.子对象有父对象属性的副本, 且这些不应该保存在子对象的prototype上. 2. ...
- css编译工具Sass中混合宏,继承,占位符分别在什么时候使用
//SCSS中混合宏使用 @mixin mt($var){ margin-top: $var; } .block { @include mt(5px); span { display:block; @ ...
- C++内存中的封装、继承、多态(上)
C++内存中的封装.继承.多态(上) 继我的上一篇文章:浅谈学习C++时用到的[封装继承多态]三个概念 此篇我们从C++对象内存布局和构造过程来具体分析C++中的封装.继承.多态. 一.封装模型的内存 ...
- javascript实现继承3种方式: 原型继承、借用构造函数继承、组合继承,模拟extends方法继承
javascript中实现继承的三种方式:原型继承.借用构造函数继承.混合继承: /* js当中的继承 js中 构造函数 原型对象 实力对象的关系: 1 构造函数.prototype = 原型对象 2 ...
- JS继承以及继承的几种实现方式总结
传统面向对象语言:继承是类与类之间的关系. 而在js中由于es6之前没有类的概念,所以继承是对象与对象之间的关系. 在js中,继承就是指使一个对象有权去访问另一个对象的能力. 比如:比如对象a能够访问 ...
随机推荐
- Javascript - ExtJs - 常用方法和属性
常用方法和属性(Common methods and attributes) ExtJs中的对象 Ext.Component Ext组件对象,表示一个可渲染的组件. Ext.dom.Element E ...
- 阿里云IoT物联网平台入门教程
参考链接:https://www.geek-workshop.com/thread-37883-1-1.html
- oracle查询语句 select a||','||b||','||c from table where a in('m','n')
查询table表中 字段a = m 或 n 时,a列,b列,c列的值,并且这三列之间用 ","(逗号)分割. 追问:连接符的作用呢?就是显示的时候链接abc和中间的逗号么?追答:| ...
- Anaconda使用总结
序 Python易用,但用好却不易,其中比较头疼的就是包管理和Python不同版本的问题,特别是当你使用Windows的时候.为了解决这些问题,有不少发行版的Python,比如WinPython.An ...
- C++ 类中特殊的成员变量(常变量、引用、静态)的初始化方法
有些成员变量的数据类型比较特别,它们的初始化方式也和普通数据类型的成员变量有所不同.这些特殊的类型的成员变量包括: a.引用 b.常量 c.静态 d.静态常量(整型) e.静态常量(非整型) 常量和引 ...
- 浅谈2017noip信息奥赛普及组试题
[话前叨叨] 一些日常刷题策略(转载): PS:本题的题目信息来自洛谷平台 下面就是进入正题了(其实这也是我第一次在csdn写博客,所以写的不好的地方也请大家多多谅解和提点/微笑/) 一.score ...
- centos7.4_x86_64安装grafana5.2.1并安装常用zabbix插件
获取并安装grafana5.2.1# wget https://s3-us-west-2.amazonaws.com/grafana-releases/release/grafana-5.2.1-1. ...
- ubuntu安装jdk8
文章连接:https://www.cnblogs.com/lighten/p/6105463.html 1.简单的安装方法 安装JDK的最简单方法应该就是使用apt-get来安装了,但是源一般是Ope ...
- zipkin 整合elastic
前提: <dependency> <groupId>io.zipkin.java</groupId> <artifactId>zipkin</ar ...
- python介绍、解释器、变量及其它
python 一.python及编程语言介绍 编程语言发展:机器语言==>汇编语言==>高级语言 机器语言:由数字电路发展而来编程都是靠0101的二进制进行 汇编语言:汇编语言的实质和机器 ...