c++ 类的继承与派生

C++ 二义性问题 二义性问题 1.在继承时,基类之间、或基类与派生类之间发生成员同名时,将出现对成员访问的不确定性——同名二义性。 2.当派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中的成员时,将产生另一种不确定性——路径二义性。 同名二义性 同名隐藏规则——解决同名二义的方法              当派生类与基类有同名成员时,派生类中的成员将屏蔽基类中的同名 阅读详情


一、基本概念

1、类的继承,是新的类从已有类那里得到已有的特性。或从已有类产生新类的过程就是类的派生。原有的类称为基类或父类,产生的新类称为派生类或子类。
 
2、派生类的声明:
class 派生类名:继承方式 基类名1, 继承方式 基类名2,...,继承方式 基类名n
{
    派生类成员声明;
};
 
3、一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个基类,称为单继承。直接派生,间接派生。
 
4、继承方式规定了如何访问基类继承的成员。继承方式有public, private, protected。如果不显示给出继承方式,默认为private继承。继承方式指定了派生类成员以及类外对象对于从基类继承来的成员的访问权限。
 
5、派生类继承基类中除构造和析构函数以外的所有成员。
 
6、派生类生成:
   吸收基类成员(除构造析构函数以外的所有成员);
   改造基类成员(根据继承方式调整基类成员的访问,函数在子类中的覆盖,以及虚函数在子类中的覆盖);
   添加新的成员;
 
7、公有继承
当类的继承方式为公有继承时,基类的公有和保护成员的访问属性在派生类中不变,而基类的私有成员不可访问。即基类的公有成员和保护成员被继承到派生类中仍作为派生类的公有成员和保护成员。派生类的其他成员可以直接访问它们。无论派生类的成员还是派生类的对象都无法访问基类的私有成员。
 
8、私有继承
当类的继承方式为私有继承时,基类中的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可访问。基类的公有成员和保护成员被继承后作为派生类的私有成员,派生类的其他成员可以直接访问它们,但是在类外部通过派生类的对象无法访问。无论是派生类的成员还是通过派生类的对象,都无法访问从基类继承的私有成员。通过多次私有继承后,对于基类的成员都会成为不可访问。因此私有继承比较少用。
 
9、保护继承
保护继承中,基类的公有成员和私有成员都以保护成员的身份出现在派生类中,而基类的私有成员不可访问。派生类的其他成员可以直接访问从基类继承来的公有和保护成员,但是类外部通过派生类的对象无法访问它们,无论派生类的成员还是派生类的对象,都无法访问基类的私有成员。
 
二、派生类的构造函数和析构函数
1、派生类中由基类继承而来的成员的初始化工作还是由基类的构造函数完成,然后派生类中新增的成员在派生类的构造函数中初始化。
 
2、派生类构造函数的语法:
派生类名::派生类名(参数总表):基类名1(参数表1),基类名(参数名2)....基类名n(参数名n),内嵌子对象1(参数表1),内嵌子对象2(参数表2)....内嵌子对象n(参数表n)
{
    派生类新增成员的初始化语句;
}
注:构造函数的初始化顺序并不以上面的顺序进行,而是根据声明的顺序初始化。
 
3、如果基类中没有不带参数的构造函数,那么在派生类的构造函数中必须调用基类构造函数,以初始化基类成员。
 
4、派生类构造函数执行的次序:
   调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左到右);
   调用内嵌成员对象的构造函数,调用顺序按照它们在类中声明的顺序;
   派生类的构造函数体中的内容。
例子:
 
复制代码
#include <iostream>
#include <time.h>
using namespace std;

class B1
{
public:
    B1(int i)
    {
        cout<<"constructing B1 "<<i<<endl;
    }
};

class B2
{
public:
    B2(int j)
    {
        cout<<"constructing B2 "<<j<<endl;
    }
};

class B3
{
public:
    B3()
    {
        cout<<"constructing B3"<<endl;
    }
};

class C: public B2, public B1, public B3
{
public:
    C(int a, int b, int c, int d):B1(a), memberB2(d), memberB1(c),B2(b)
    {

    }
private:
    B1 memberB1;
    B2 memberB2;
    B3 memberB3;
};

int main() 
{ 
    C obj(1,2,3,4);

    return 0; 
}
复制代码

 

 
输出结果为:
constructing B2 2
constructing B1 1
constructing B3
constructing B1 3
constructing B2 4
constructing B3
 
5、析构函数
派生类的析构函数的功能是在该对象消亡之前进行一些必要的清理工作,析构函数没有类型,也没有参数。析构函数的执行顺序与构造函数相反。
例子:
复制代码
#include <iostream>
#include <time.h>
using namespace std;

class B1
{
public:
    B1(int i)
    {
        cout<<"constructing B1 "<<i<<endl;
    }
    ~B1()
    {
        cout<<"destructing B1"<<endl;
    }
};

class B2
{
public:
    B2(int j)
    {
        cout<<"constructing B2 "<<j<<endl;
    }
    ~B2()
    {
        cout<<"destructing B2"<<endl;
    }
};

class B3
{
public:
    B3()
    {
        cout<<"constructing B3"<<endl;
    }
    ~B3()
    {
        cout<<"destructing B3"<<endl;
    }
};

class C: public B2, public B1, public B3
{
public:
    C(int a, int b, int c, int d):B1(a), memberB2(d), memberB1(c),B2(b)
    {

    }
private:
    B1 memberB1;
    B2 memberB2;
    B3 memberB3;
};

int main() 
{ 
    C obj(1,2,3,4);

    return 0; 
}
复制代码

 

输出结果为:
constructing B2 2
constructing B1 1
constructing B3
constructing B1 3
constructing B2 4
constructing B3
destructing B3
destructing B2
destructing B1
destructing B3
destructing B1
destructing B2
 
三、派生类成员的标识和访问
1、派生类成员属性划分为四种:
   不可访问的成员;私有成员;保护成员;公有成员;
 
2、作用域分辨
形式为:基类名::成员名;基类名::成员名(参数表);
如果某派生类的多个基类拥有同名的成员,同时,派生类又新增这样的同名成员,在这种情况下,派生类成员将覆盖所有基类的同名成员。这就需要这样的调用方式才能调用基类的同名成员。
例子:多继承同名 
 
复制代码
#include <iostream>
#include <time.h>
using namespace std;

class B1
{
public:
    int nV;
    void fun()
    {
        cout<<"member of B1 "<<nV<<endl;
    }
};

class B2
{
public:
    int nV;
    void fun()
    {
        cout<<"member of B2 "<<nV<<endl;
    }
};

class D1: public B1, public B2
{
public:
    int nV;
    void fun()
    {
        cout<<"member of D1 "<<nV<<endl;
    }
};

int main() 
{ 
    D1 d1;
    d1.nV = 1;
    d1.fun();
    d1.B1::nV = 2;
    d1.B1::fun();
    d1.B2::nV = 3;
    d1.B2::fun();

    return 0; 
}
复制代码

 

输出结果为:
member of D1 1
member of B1 2
member of B2 3
以上通过作用域分辨符,解决了访问基类中被屏蔽的同名成员。
 
3、如果某个派生类的部分或全部直接基类是从另一个共同的基类派生而来,在这些直接基类中,从上一级基类继承来的成员就拥有相同的名称,因此派生类中也就会产生同名现象,对这种类型的同名成员也要使用作用域分辨符来唯一标识,而且必须用直接基类进行限定。
例子:
复制代码
#include <iostream>
#include <time.h>
using namespace std;

class B0
{
public:
    int nV;
    void fun()
    {
        cout<<"member of B0 "<<nV<<endl;
    }
};

class B1:public B0
{
public:
    int nV1;
};

class B2:public B0
{
public:
    int nV2;
};

class D1:public B1, public B2
{
public:
    int nVd;
    void fund()
    {
        cout<<"member of D1"<<endl;
    }
};

int main() 
{ 
    D1 d1;
    d1.B1::nV = 2;
    d1.B1::fun();
    d1.B2::nV = 3;
    d1.B2::fun();

    return 0; 
}
复制代码

 

输出结果为:
member of B0 2
member of B0 3
在这种情况下,派生类对象在内存中就同时拥有成员nV及fun的两份拷贝。但是很多情况下,我们只需要这样一个这样的数据拷贝,同一成员的多份拷贝增加了内存的开销。可以通过虚函数来解决这个问题。
 
4、虚基类
为了解决前面提到的多重拷贝的问题,可以将共同基类设置为虚基类,这时从不同的路径继承过来的同名数据成员在内存中就只有一个拷贝,同一个函数也只有一个映射。
虚基类的声明是在派生类的声明过程,其语法形式为:
class 派生类名::virtual 继承方式 基类名;
例子:
复制代码
#include <iostream>
#include <time.h>
using namespace std;

class B0
{
public:
    int nV;
    void fun()
    {
        cout<<"member of B0 "<<nV<<endl;
    }
};

class B1:virtual public B0
{
public:
    int nV1;
};

class B2:virtual public B0
{
public:
    int nV2;
};

class D1:public B1, public B2
{
public:
    int nVd;
    void fund()
    {
        cout<<"member of D1"<<endl;
    }
};

int main() 
{ 
    D1 d1;
    d1.nV = 2;
    d1.fun();

    return 0; 
}
复制代码

 

输出结果为:
member of B0 2
 
5、虚基类及其派生类的构造函数
一般而言,派生类只对其直接基类的构造函数传递参数,但是在虚基类中,不管是直接或间接虚基类的所有派生类,都必须在构造函数的成员初始化列表中列出对虚基类的初始化。
例子:
复制代码
#include <iostream>
#include <time.h>
using namespace std;

class B0
{
public:
    B0(int n)
    {
        nV = n;
    }
    int nV;
    void fun()
    {
        cout<<"member of B0 "<<nV<<endl;
    }
};

class B1:virtual public B0
{
public:
    B1(int a):B0(a)   
    {
    }
    int nV1;
};

class B2:virtual public B0
{
public:
    B2(int a):B0(a)
    {
    }
    int nV2;
};

class D1:public B1, public B2
{
public:
    D1(int a):B0(a), B1(a), B2(a)
    {
    }
    int nVd;
    void fund()
    {
        cout<<"member of D1"<<endl;
    }
};

int main() 
{ 
    D1 d1(1);
    d1.nV = 2;
    d1.fun();

    return 0; 
}
复制代码

 

以上例子看上去B0的构造函数好像被调用了三次,但是实际上只有D1类中的D1(int a):B0(a), B1(a), B2(a)
才是真正的调用了B0构造函数。
 
四、赋值兼容规则
1、赋值兼容规则是指在需要基类对象的任何地方都可以使用公有派生类的对象来替代。
2、赋值兼容规则中所指的替代包括:
   派生类的对象可以赋值给基类对象;
   派生类的对象可以初始化基类的引用;
   派生类对象的地址可以赋给指向基类的指针。
   在替代之后,派生类对象就可以作为基类的对象使用,但只能使用从基类继承的成员。
例子:
复制代码
#include <iostream>
#include <time.h>
using namespace std;

class B0
{
public:
    void display()
    {
        cout<<"B0::display()"<<endl;
    }
};

class B1:public B0
{
public:
    void display()
    {
        cout<<"B1::display()"<<endl;
    }
};

class B2:public B0
{
public:
    void display()
    {
        cout<<"B2::display()"<<endl;
    }
};

void fun(B0 *ptr)
{
    ptr->display();
}

int main() 
{ 
    B0 b0;
    B1 b1;
    B2 b2;
    fun(&b0);
    b0 = b1;
    fun(&b0);
    b0 = b2;
    fun(&b0);

    return 0; 
}
复制代码

 

 

输出结果为:

B0::display()

B0::display()

B0::display()

通过这种赋值兼容后,每次调用的同名函数都是基类的同名函数,如果想调用派生类的,则需要使用虚函数。

C++基类与派生类 class : private:派生类新增成员;protected:派生类新增成员;public:派生类新增成员;说明:(1)class:类声明的关键字;(2)派生类名:新(派生)类名;(3)继承方式:指出继承的方式是什么。继承方式包含以下3种。• public(公有继承方式)使用的最多;• private(私有继承方式);• protected(保护继承方式)。用来说明对于从基类继承来的成员的访问权限,这个稍后介绍。 阅读详情

相关推荐

C/C++ 类的继承与派生

before|正文之前: c++实验代码及学习笔记(九) 你好! 这是一个高程实验课的代码记录及学习笔记。我将记录一些重要的知识点、易错点。但是作为大学生,水平很低,敬请指点教导、优化代码。 1问题 本节课我们学习了类的继承和派生,单继承、多重继承、多继承与虚基类等知识。 这道题实际上就是对知识的直接考察,故本次笔记侧重于对知识的罗列。 2精讲 参考文章:C++ 类的继承与派生 C++中的继...

duoluka的博客 3594

类的继承与派生

类及对象的访问权限: 类中的成员函数可以直接访问类中的数据成员(包括私有成员、公有成员、保护成员); 类中的成员函数可以相互访问; 类的对象只能访问类的公有成员,不能访问私有成员及保护成员。 一、继承与派生 在C++中,类具有继承性,所谓继承就是在一个已存在的类的基础上建立一个新的类。 利用类的继承,可以将原来的程序代码重复使用,从而减少了程序代码的冗余度,符合软件重用的目标。增强编程语言的功能。提高软件开发效率。 在继承关系中,被继承的类称为基类(或父类),把通过继承关......

swint_er的博客 9553

C++ 课程作业 继承与派生(Shape Circle Rectangle类的设计,继承与派生)

首先是题目 【问题描述】 编写一个Shape类并派生出Circle类和Rectangle类,观察运行机制。 shape类有以下成员 1)私有成员m_ID 2)公有getter和setter 3)计算面积函数getArea(),返回0; 4)构造与析构函数 Circle类从shape类继承,并派生以下成员 1)私有成员r 2)公有getter和setter 3)计算面积函数getArea(),返回计...

salix_mark的博客 3046

C++类——派生类的定义、构成及访问控制

面向对象程序设计   面向对象程序设计(OOP)的核心思想是数据抽象、 继承和动态绑定。 使用数据抽象, 我们可以将类的接口与实现分离(封装)。 使用继承, 我们可以定义相似的类型并对其相似关系建模。 使用动态绑定, 可以在一定程度上忽略相似类型的区别, 而以统 一的方式使用它们的对象(多态) 类之间的关系   类之间的三种关系: 包含关系(has-A) class B{...

xiaokunzhang的博客 4万+

vivado运行时报错 license文件更新操作

vivado使用:SYNTHESIS->Run Synthesis 时报错 [Common 17-345] A valid license was not found for feature ‘Synthesis’ and/or device ‘xc7vx485t’. Please run the Vivado License Manager for assistance in determiningwhich features and devices are licensed for your sy

qq_44692266的博客 2万+

ABAP代码检查(Code Review)

1、SLIN 扩展程序检查 也可通过(SE38工具栏->检查-扩展程序检查) 进入 2、ATC 检查 通过<SE38菜单栏-检查-ABAP测试主控室> 或事物代码SCI, 支持自定义检查变式 SCI可以配置检查变式满足特殊需求,配置对象集用于批量检查 3、通过ABAP测试主控室实现统一管理,定期检查作业和监控功能(事务代码ATC) 参考 SLIN...

u012232542的博客 6063

C++类的继承与派生

文章目录一、继承二、基类和派生类三、继承方式六、多继承七、应用经验八、课后作业九、版权声明 一、继承 继承是面向对象程序设计中最重要的一个概念。继承允许我们根据一个类来定义另一个类,达到了代码功能重用效果。 当创建一个类时,如果待创建的类与另一个类存在某些共同特征,程序员不需要全部重新编写成员变量和成员函数,只需指定继承另一个类即可,被继承的类称为基类或父类,新建的类称为派生类或子类。 二、基类和...

C语言技术网-码农有道 457

wsl2上运行带有Isaac Gym的程序报错: GPU Pipeline: disabled

显示GPU Pipeline:disabled,查找相关文档发现是WSL2目前不支持Isaac Gym,时,想要在wsl2上运行,最后报错如下。

2303_78660611的博客 957

c++类之继承与派生

继承与派生 我们首先通过一个程序来总结

u011484045的专栏 1263

Windows系统下LaTeX环境搭建与编辑器配置全攻略

本文详细介绍了在Windows系统下搭建LaTeX环境的完整流程,包括TeX Live的安装、TeXStudio编辑器的配置优化以及常见问题排查。特别针对中文用户推荐使用清华镜像源加速下载,并提供了XeLaTeX编译器配置、中文支持等实用技巧,帮助用户快速上手LaTeX文档编写。

weixin_42554408的博客 449

告别眼疲劳!保姆级教程:给你的SecureCRT v8.7.2换上护眼高亮配色(附透明背景设置)

本文提供了一份详细的SecureCRT v8.7.2护眼高亮配色方案教程,帮助程序员缓解眼疲劳问题。通过科学调整配色方案、动态环境自适应设置以及字体渲染优化,显著提升终端使用的舒适度和工作效率。特别推荐Solarized Dark和One Dark Pro医学适配版配色方案,适合长时间编码工作。

weixin_42549496的博客 354

C++程序设计【五】之 类的继承与派生

感谢内容提供者:金牛区吴迪软件开发工作室 文章目录第五章:类的继承与类的派生一、类的继承与类的派生1.继承的概念2.派生类的定义与大小a.派生类的定义b.类的大小c.继承关系的特殊性3.继承关系的特殊性4.有继承关系的类之间的访问5.protected访问范围说明符6.多重继承二、访问控制1.公有继承2.类型兼容规则3.私有继承4.保护继承三、派生类的构造函数和析构函数1.构造函数与析构函数2.复制构造函数3.多重继承的构造函数与析构函数四、类之间的关系1.类与类之间的关系2.封闭类的派生3.互包含关系.

吴小迪的博客 2156

从波形到代码:手把手调试GaN图腾柱PFC的过零点切换与软启动策略

本文详细解析了GaN图腾柱无桥Boost PFC电路在过零点切换与软启动策略中的调试方法。通过波形分析、代码实现和寄存器配置,提供了解决误开通、震荡波形等问题的实用方案,帮助工程师优化电源设计效率与可靠性。

weixin_30831529的博客 422

C++学习手记(二)——类的继承与派生

                                C++学习手记(二)——类的继承与派生                                                          陈根发    由于类与对象的存在,使得C++变得具有更强大的生命力,这也是C++产生的原因之一。但是C++面对对象的魔力到底在那呢?昨天开始我逐渐感觉出来了!那就是类三大特性——封装

chenyu001的专栏 1750

OPTEE v4.4.0 qemu_v8环境搭建(支持Hafnium)

一、前提条件 二、拉取代码 三、下载工具链 四、修改代码 五、编译 六、运行

AI-安全-功耗 889

基于Python的船舶AIS数据爬取与分析:从数据采集到可视化实战

本文详细介绍了如何使用Python构建一个完整的船舶AIS数据爬取与分析系统。文章从AIS系统的基本原理讲起,逐步深入到数据采集、存储、清洗、分析和可视化的全流程。我们将使用最新的Python技术栈,包括aiohttp异步爬虫、MongoDB存储、Pandas数据处理以及Pydeck三维可视化等。本文提供了完整的代码实现,并探讨了在实际应用中可能遇到的问题及其解决方案。关键词:AIS数据、Python爬虫、异步IO、数据可视化、海事分析。

2201_76125261的博客 811

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

[C++]类的继承与派生 继承性是面向对象程序设计的第二大特性,它允许在既有类的基础上创建新类,新类可以继承既有类的数据成员和成员函数,可以添加自己特有的数据成员和成员函数,还可以对既有类中的成员函数重新定义。利用类的继承和派生实现了更高层次的代码可重用性,符合现代软件开发的思想。 C++语言同时支持单一继承和多重继承。单一继承是指派生类只从一个基类继承而来;相应的,多重继承指派生类同时从两个或更多的基类继承而来。java只支持单一继承。 一. 派生类 派生类的定义格式如下: class &

wmy0536的博客 656

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

【C++学习笔记】类的继承与派生

0x00 前言 文章中的文字可能存在语法错误以及标点错误,请谅解; 如果在文章中发现代码错误或其它问题请告知,感谢! 本文档为个人边学习边记录的C++笔记,非教程,笔记中会存在引用他人文章内容的部分,被引用的原文不会被特殊标记出来,但会在参考文档中给出原文链接。 0x01 类的继承与派生 面向对象的程序设计中提供了雷得继承机制,允许程序员在保持原有类特性的基础上,进行更具体、更详细的类的定义。以原有的类为基础产生新的类,我们就说新类继承了原有类的特征,也可以说是从原有类派生出新类。类的派生机制好处在于代码的

C/C++攻城狮 708

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

类的继承和派生java_C++ 类的继承与派生实例详解

C++ 类的继承与派生实例详解继承性是面向对象程序设计最重要的特性之一,使软件有了可重用性,C++提供的类的继承机制。继承与派生的概念一个新类从已有的类那里获得已有的特性,这种现象称为类的继承。同样也可以说成已有的类派生出来了新的类。类A继承自类B也就是类B派生了类A。所以继承和派生的关系就像小学时把字句和被字句的造句一样。有了继承与派生后,就有了父类/基类与子类/派生类,C++中将类B称为父类/...

weixin_33583419的博客 212

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

上一篇: gcc编译C++程序
下一篇: vim常用命令
csshuke
博客等级 码龄16年 1517粉丝 8原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值