1继承概念

面向对象程序设计有4个主要特点:抽象、封装、继承和多态性。说了类和对象,了解了面向对象程序设计的两个重要特征一数据抽象与封装,已经能够设计出基于对象的程序,这是面向对象程序设计的基础。

要较好地进行面向对象程序设计,还必须了解面向对象程序设计另外两个重要特 征——继承性和多态性。本章主要介绍有关继承的知识,多态性将在后续章节中讲解。

继承性是面向对象程序设计最重要的特征,可以说,如果没有掌握继承性,就等于没有掌握类和对象的精华,就是没有掌握面向对象程序设计的真谛。

1.1类之间的关系

has-A,uses-A 和 is-A

has-A 包含关系,用以描述一个类由多个"部件类"构成。实现has-A关系用类成员表示,即一个类中的数据成员是另一种已经定义的类。

uses-A 一个类部分地使用另一个类。通过类之间成员函数的相互联系,定义友员或对象参数传递实现。

is-A 机制称为"继承"。关系具有传递性,不具有对称性。

1.2继承关系举例

万事万物中皆有继承,是重要的现象

两个案例:1)植物继承图;2)程序员继承图

1.3 继承相关概念

1.4 派生类的定义

注意:C++中的继承方式(public、private、protected)会影响子类的对外访问属性。

 

1.5 继承重要说明

1、子类拥有父类的所有成员变量和成员函数

2、子类可以拥有父类没有的方法和属性

3、子类就是一种特殊的父类

4、子类对象可以当作父类对象使用

2派生类的访问控制

派生类继承了基类的全部成员变量和成员方法(除了构造和析构之外的成员方法),但是这些成员的访问属性,在派生过程中是可以调整的。

2.1单个类的访问控制

1、类成员访问级别(public、private、protected)

2、思考:类成员的访问级别只有public和private是否足够?

2.2不同的继承方式会改变继承成员的访问属性

1)C++中的继承方式会影响子类的对外访问属性

public继承:父类成员在子类中保持原有访问级别

private继承:父类成员在子类中变为private成员

protected继承:    父类中public成员会变成protected

父类中protected成员仍然为protected

            父类中private成员仍然为private

2)private成员在子类中依然存在,但是却无法访问到。不论种方式继承基类,派生类都不能直接使用基类的私有成员 。

3)C++中子类对外访问属性表

 

父类成员访问级别

 

public

proteced

private

public

public

proteced

private

proteced

proteced

proteced

private

private

private

private

Private

 

4)继承中的访问控制

这个图说的是:public继承:父类的a可以在main函数中(即类外)访问;b,c不能访问;protected、private继承的方式父类的成员都不能在函数中(类外)访问到。

2.3"三看"原则

C++中的继承方式(public、private、protected)会影响子类的对外访问属性    

判断某一句话,能否被访问

    1)看调用语句,这句话写在子类的内部、外部

    2)看子类如何从父类继承(public、private、protected)    

    3)看父类中的访问级别(public、private、protected)

2.3派生类类成员访问级别设置的原则

    思考:如何恰当的使用public,protected和private为成员声明访问级别?

1、需要被外界访问的成员直接设置为public

2、只能在当前类中访问的成员设置为private

3、只能在当前类和子类中访问的成员设置为protected,protected成员的访问权限介于public和private之间。

2.4综合

练习:

public继承不会改变父类对外访问属性;

private继承会改变父类对外访问属性为private;

protected继承会部分改变父类对外访问属性。

结论:一般情况下class B : public A:一般都是公有继承父类

//类的继承方式对子类对外访问属性影响

 

#include
<cstdlib>

#include
<iostream>

 

using
namespace std;

 

class
A

{

private:

    int a;

protected:

    int b;

public:

    int c;

 

    A()

    {

        a = 0;

        b = 0;

        c = 0;

    }

 

    void set(int
a, int
b, int
c)

    {

        this->a = a;

        this->b = b;

        this->c = c;

    }

};

 

class
B : public
A

{

public:

    void print()

    {

        //cout<<"a = "<<a; //err

        cout <<
"b = "
<< b;

        cout <<
"c = "
<< endl;

    }

};

 

class
C : protected
A

{

public:

    void print()

    {

        //cout<<"a = "<<a; //err

        cout <<
"b = "
<< b;

        cout <<
"c = "
<< endl;

    }

};

 

class
D : private
A

{

public:

    void print()

    {

        //cout<<"a = "<<a; //err

        cout <<
"b = "
<< b << endl;

        cout <<
"c = "
<< c << endl;

    }

};

 

int main_01(int
argc, char *argv[])

{

    A aa;

    B bb;

    C cc;

    D dd;

 

    aa.c = 100; //ok

    bb.c = 100; //ok

                //cc.c = 100; //err 类的外部是什么含义

                //dd.c = 100; //err

 

    aa.set(1, 2, 3);

    bb.set(10, 20, 30);

    //cc.set(40, 50, 60); //ee

    //dd.set(70, 80, 90); //ee

 

    bb.print();

    cc.print();

    dd.print();

 

    system("pause");

    return 0;

}

3继承中的构造和析构

3.1类型兼容性原则

类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派 生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。类型兼容规则中所指的替代包括以下情况:

子类对象可以当作父类对象使用

子类对象可以直接赋值给父类对象

子类对象可以直接初始化父类对象

父类指针可以直接指向子类对象

父类引用可以直接引用子类对象

在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员。

类型兼容规则是多态性的重要基础之一。

 

总结:子类就是特殊的父类 (base *p = &child;)

#include
<cstdlib>

#include
<iostream>

 

using
namespace std;

 

/*

子类对象可以当作父类对象使用

子类对象可以直接赋值给父类对象

子类对象可以直接初始化父类对象

父类指针可以直接指向子类对象

父类引用可以直接引用子类对象

*/

//子类就是特殊的父类

class
Parent03

{

protected:

    const
char* name;

public:

    Parent03()

    {

        name = "Parent03";

    }

 

    void print()

    {

        cout <<
"Name: "
<< name << endl;

    }

};

 

class
Child03 : public
Parent03

{

protected:

    int i;

public:

    Child03(int
i)

    {

        this->name = "Child2";

        this->i = i;

    }

};

 

int main()

{

    Child03 child03(1000);

    //分别定义父类对象 父类指针 父类引用 child

    Parent03 parent = child03;

    Parent03* pp = &child03;

    Parent03& rp = child03;

 

    parent.print();

    pp->print();

    rp.print();

    system("pause");

    return 0;

}

 

3.2继承中的对象模型

类在C++编译器的内部可以理解为结构体

子类是由父类成员叠加子类新成员得到的

 

继承中构造和析构

问题:如何初始化父类成员?父类与子类的构造函数有什么关系

    在子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初始化

    在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清理

#include
<cstdlib>

#include
<iostream>

using
namespace std;

 

class
Parent04

{

public:

    Parent04(const
char* s)

    {

        cout <<
"Parent04()"
<<
" "
<<
s
<< endl;

    }

 

    ~Parent04()

    {

        cout <<
"~Parent04()"
<< endl;

    }

};

 

class
Child04 : public
Parent04

{

public:

    Child04() : Parent04("Parameter from Child!")

    {

        cout <<
"Child04()"
<< endl;

    }

 

    ~Child04()

    {

        cout <<
"~Child04()"
<< endl;

    }

};

 

void run04()

{

    Child04 child;

}

 

int main_04(int
argc, char *argv[])

{

    run04();

 

    system("pause");

    return 0;

}

 

3.3继承中的构造析构调用原则

1、子类对象在创建时会首先调用父类的构造函数

2、父类构造函数执行结束后,执行子类的构造函数

3、当父类的构造函数有参数时,需要在子类的初始化列表中显示调用

4、析构函数调用的先后顺序与构造函数相反

3.4继承与组合混搭情况下,构造和析构调用原则

    原则:    先构造父类,再构造成员变量、最后构造自己

             先析构自己,在析构成员变量、最后析构父类

            //先构造的对象,后释放

 

 

//子类对象如何初始化父类成员

//继承中的构造和析构

//继承和组合混搭情况下,构造函数、析构函数调用顺序研究

 

#include
<iostream>

 

using
namespace std;

 

class
Object

{

public:

    Object(const
char* s)

    {

        cout <<
"Object()"
<<
" "
<<
s
<< endl;

    }

    ~Object()

    {

        cout <<
"~Object()"
<< endl;

    }

};

 

class
Parent : public
Object

{

public:

    Parent(const
char* s) : Object(s)

    {

        cout <<
"Parent()"
<<
" "
<<
s
<< endl;

    }

    ~Parent()

    {

        cout <<
"~Parent()"
<< endl;

    }

};

 

class
Child : public
Parent

{

protected:

    Object o1;

    Object o2;

public:

    Child() : o2("o2"), o1("o1"), Parent("Parameter from Child!")

    {

        cout <<
"Child()"
<< endl;

    }

    ~Child()

    {

        cout <<
"~Child()"
<< endl;

    }

};

 

void run05()

{

    Child child;

}

 

int main05(int
argc, char *argv[])

{

    cout <<
"demo05_extend_construct_destory.cpp"
<< endl;

    run05();

 

    system("pause");

    return 0;

}

3.5继承中的同名成员变量处理方法

当子类成员变量与父类成员变量同名时,子类依然从父类继承同名成员,在子类中通过作用域分辨符::进行同名成员区分(在派生类中使用基类的同名成员,显式地使用类名限定符)。同名成员存储在内存中的不同位置

 

总结:同名成员变量和成员函数通过作用域分辨符进行区分

 

3.6派生类中的static关键字

继承和static关键字在一起会产生什么现象哪?

理论知识

  • 基类定义的静态成员,将被所有派生类共享
  • 根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具有不同的访问性质 (遵守派生类的访问控制)
  • 派生类中访问静态成员,用以下形式显式说明:

            类名 :: 成员

或通过对象访问    对象名 . 成员

总结:

1> static函数也遵守3个访问原则

2> static易犯错误(不但要初始化,更重要的显示的告诉编译器分配内存)

3> 构造函数默认为private

4多继承

4.1多继承的应用

多继承概念

  • 一个类有多个直接基类的继承关系称为多继承
  • 多继承声明语法

class 派生类名 : 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n

{

数据成员和成员函数声明

};

  • 类 C 可以根据访问控制同时继承类 A 和类 B 的成员,并添加

自己的成员

多继承的派生类构造和访问

  • 多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员
  • 执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。
  • 一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性。如果不同的基类有同名成员,派生类对象访问时应该加以识别。

 

多继承简单应用

 

4.2虚继承

如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性

 

分析:

总结:

  • 如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性
  • 如果在多条继承路径上有一个公共的基类,那么在继承路径的某处汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象,要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类。
  • 虚继承声明使用关键字     virtual

 

 

 

实验:注意增加virtual关键字后,构造函数调用的次数。

5继承总结

  • 继承是面向对象程序设计实现软件重用的重要方法。程序员可以在已有基类的基础上定义新的派生类。
  • 单继承的派生类只有一个基类。多继承的派生类有多个基类。
  • 派生类对基类成员的访问由继承方式和成员性质决定。
  • 创建派生类对象时,先调用基类构造函数初始化派生类中的基类成员。调用析构函数的次序和调用构造函数的次序相反。
  • C++提供虚继承机制,防止类继承关系中成员访问的二义性。
  • 多继承提供了软件重用的强大功能,也增加了程序的复杂性。

C++复习:继承与派生的更多相关文章

  1. Day08:继承与派生,多态,封装,绑定与非绑定方法,面向对象高级(反射,__str__,__del__)

    上节课复习:1.编程思想    面向过程        核心是过程二字,过程指的是解决问题的步骤,即先干什么再干什么后干什么        基于该思想编写程序就好比在设计一条流水线,是一种机械式的思维 ...

  2. c++学习--继承与派生

    继承和派生 1 含有对象成员(子对象)的派生类的构造函数,定义派生类对象成员时,构造函数的执行顺序如下: 1 调用基类的构造函数,对基类数据成员初始化: 2 调用对象成员的构造函数,对对象成员的数据成 ...

  3. 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成员)

    [源码下载] 不可或缺 Windows Native (21) - C++: 继承, 组合, 派生类的构造函数和析构函数, 基类与派生类的转换, 子对象的实例化, 基类成员的隐藏(派生类成员覆盖基类成 ...

  4. [C++]类的继承与派生

    继承性是面向对象程序设计的第二大特性,它允许在既有类的基础上创建新类,新类可以继承既有类的数据成员和成员函数,可以添加自己特有的数据成员和成员函数,还可以对既有类中的成员函数重新定义.利用类的继承和派 ...

  5. O-c中类的继承与派生的概念

    什么是继承 众所周知,面向对象的编程语言具有: 抽象性, 封装性, 继承性, 以及多态性 的特征. 那么什么是继承呢? 传统意义上是指从父辈那里获得父辈留下的东西 在开发中, 继承就是"复用 ...

  6. 程序设计实习MOOC / 继承和派生——编程作业 第五周程序填空题1

    描述 写一个MyString 类,使得下面程序的输出结果是: 1. abcd-efgh-abcd- 2. abcd- 3. 4. abcd-efgh- 5. efgh- 6. c 7. abcd- 8 ...

  7. 走进C++程序世界------继承和派生

    继承和派生 继承是面向对象编程语言的最重要方面之一,正确的使用继承可编写出设计良好,容易于维护和扩展的应用程序.下面是在其他博客中的总结: ****************************** ...

  8. C++学习之路—继承与派生(一):基本概念与基类成员的访问属性

    (本文根据<c++程序设计>(谭浩强)总结而成,整理者:华科小涛@http://www.cnblogs.com/hust-ghtao,转载请注明) 1   基本思想与概念 在传统的程序设计 ...

  9. C/C++基础知识总结——继承与派生

    1. 类的继承与派生 1.1 派生类的定义 (1) 定义规范 class 派生类名: 继承方式 基类1名, 继承方式 基类2名... { ...派生类成员声明; }; (2) 从以上形式上看可以多继承 ...

随机推荐

  1. python之路——2

    王二学习python的笔记以及记录,如有雷同,那也没事,欢迎交流,wx:wyb199594 复习 1.编译型:一次性将全部的代码编译成二进制文件 c c++ 优点:运行效率高 缺点:开发速度慢,不能跨 ...

  2. [UE4]多播(广播)

    只有服务器才有权限做广播,所以要判断确保是服务器端才做广播,有以下几种方法: 一.使用“Switch Has Authority”判断是否在服务器端 因为character一定是在服务器端创建出来的, ...

  3. UE4中多种颜色轮廓线的后期处理

    转自:http://blog.csdn.net/pizi0475/article/details/50396277 随着近来虚幻引擎4的一些变化,渲染多种颜色的轮廓线已经可以实现了!通过自定义模板,类 ...

  4. MySQL 之 MyTop实时监控MySQL

    CentOS下使用MyTop实时监控MySQL MyTop的项目页面为:http://jeremy.zawodny.com/mysql/mytop/ MyTop安装 安装依赖包  yum instal ...

  5. XML与 实体的相互转化

    using System; using System.Linq; using System.Xml; using System.Reflection; using System.Data; using ...

  6. 使用Keepalived实现linux高可用集群

    安装 apt install libipset-dev keepalived -y 创建账户 useradd -s/usr/sbin/nologin -M -g root keepalived_scr ...

  7. CS229 2.深入梯度下降(Gradient Descent)算法

    1 问题的引出 对于上篇中讲到的线性回归,先化一个为一个特征θ1,θ0为偏置项,最后列出的误差函数如下图所示: 手动求解 目标是优化J(θ1),得到其最小化,下图中的×为y(i),下面给出TrainS ...

  8. The Kernel Boot Process.内核引导过程

    原文标题:The Kernel Boot Process 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精彩文章翻译一下.一来自己 ...

  9. 《Linux性能及调优指南》第二章:监控和基准工具2.1-2.2

    翻译:飞哥 (http://hi.baidu.com/imlidapeng) 版权所有,尊重他人劳动成果,转载时请注明作者和原始出处及本声明. 原文名称:<Linux Performance a ...

  10. TP框架做网页静态化

    首先放上一张某手册中的一段代码: 我们要想在TP框架中执行网页静态化,在这段代码的基础上稍加添加就可以了: 在TP5框架中,为了方便寻找模板文件与生成的静态文件,我们将模板文件以及生成的静态文件放在p ...