浅论继承与派生

2023-11-11 09:31
文章标签 继承 浅论 派生

本文主要是介绍浅论继承与派生,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

都说继承派生是c++的精髓,就如同指针是c的灵魂一样。
最近刚好学到这些知识,就写一个博客分享下学习体会吧。

继承与派生
啥叫继承呢,就比如你爸爸在外面拼搏开了个厂子,等你老爸退休不做让位给你了,那么你就是继承着你老爸的厂子。什么叫派生呢?好比你自己长大了有出息了,自己赚了钱买了个车,这车就是你派生出来的东西,说个不恰当的,就是你爸爸的钱,厂子,车子你全继承下来了,但是车型号太老了你不喜欢,你自己买了个新的,那么你比你爸爸就多了个新的车子。
继承和派生就好比是这样,你爸爸的东西你继承下来了,你自己还新派生了些东西,换句话说,你爸爸有的你都有,你爸爸没有的你也有。
那么接下来举个例子吧。

#include <iostream>
#include "string.h"using namespace std;class Parent
{
public:int money;
public:Parent(int _p){cout << "Parent 构造函数" << endl;money = _p;}void showp(){cout << "this is parent  :" << money << "万" << endl;}
};class Child : public Parent
{
public:char *car;
public:Child(int _p, char *n) : Parent(_p){cout << "Child 构造函数" << endl;car = new char [100];strcpy(car,n);}void showc(){cout << "this is child   :" << car << endl;}	
};int main()
{Child ch(100, "Audi");cout << "*************************" << endl;ch.showp();ch.showc();return 0;
}

访问控制权限问题
上述例子中,假设你大名是ch,那么你show出来的东西既有你继承你爸爸的100万,还有一辆属于你的奥迪车。
这边顺带就接着讲一讲一些权限吧,你父亲的东西有个权限,而你继承过来之后,也有一个权限,就比如,你父亲用作打麻将的小金库,在你父亲那边应该是private私有权限,你父亲是不会让你继承的吧,你连这个都继承来了你父亲过年拿什么坐庄呢?还有一个权限,是你自己继承来之后的权限,比如你父亲的车子,有句话叫老婆与车恕不外借,对吧,那么你父亲的车你可以继承过来,但是在你这儿就是你私有的,不外借。关于权限,public,protected,private,三种,两层关系,组合起来细分就是九种,按照我的想法,就是取其权限最小者作为最终的权限。

class Father
{
private:int money; //你老爸打麻将的
protected:int card;  // 你爸爸的银行卡,只能你家人用,外人不能用
public:int fangchan; // 你家的房产,你亲戚来了可以借助
};//继承权限
class MR_Wang : public Father   //你继承来之后的权限
{
private: char your_car; //你的车,私有的权限,不外借
protected:int computer; // 你的电脑,别人可以玩,但是不能带出去玩
public:int You_Hui_Quan;//你的兰博基尼五元代金券,可以直接送你朋友用
};

这里举的例子可能不恰当,但是有助于理解,即在你父亲的权限,你的继承权限中最小值作为你的最终的权限。
接下来再来谈谈继承派生中构造函数和析构函数吧。还是以你爸爸的资产和你继承与派生的资产为例子。你爸爸去申请的办理的银行卡,肯定得你爸爸本人的身份证,那么当你爸爸想要提出大笔金额时,还得你爸爸带着证件去银行,在这里就可以把你爸爸的身份证当作是一个构造函数,那么当你结婚买房需要大额money时候,还需要你爸爸 带着证件去银行取钱,参数初始化列表Child(int money, char *name, int x) : Parent(monet, name); 就好比你带着你爸爸去银行,取出来钱给你用。这就是析构函数,你没办法直接取银行卡里的钱,但是你可以喊上你爸爸带着证件去取钱。
这个过程是需要你参与的,但是析构函数就不用你再去过问了,换句话说析构函数,不要人为干预了,就好比你爸爸的一双鞋子破旧不想要了,你爸爸带你妈妈shopping一圈自己去买一双就ok了。

继承时的名字遮蔽
接下来再来讨论一下一个问题,比如你朋友来你家做客,看见你家有个大鱼缸,里面的鱼甚是好看,而里面的鱼既有你爸爸垂钓得来,也有你买来的,你朋友对其饶有兴趣,那么默认情况下,你的朋友就会以为这里面的鱼都是你弄来的,如果你给你朋友做了介绍说明这里面有的鱼是你父亲垂钓所得,那么你朋友才会知道真相并夸赞你的父亲。

#include <iostream>using namespace std;class Parent
{
public:char *s1;Parent(){s1 = new char [100];strcpy(s1, "fish");}void fish(){cout << s1 << " by father" << endl;}
};class Child : public Parent
{
public:char *s2;Child(){s2 = new char [100];strcpy(s2, "fish");}void fish(){cout << s2 << " by myself" <<  endl;}
};int main()
{ Child f;f.fish();cout << "*************" << endl;f.Parent::fish();return 0;
}

在这里插入图片描述
这个例子实际上说的就是 继承时候的名字遮蔽问题,就如同这些鱼,你朋友默认是你掉来的,只有在你说明之后,你朋友才会知道有些是你父亲掉来的。

继承中的static关键字
还是接上面的某个例子来说吧,比如你爸爸银行卡里面的钱,你爸爸取钱或者你去存钱,里面的数据修改了会被记录下来,这个时候就需要一个全局静态变量, 比如 static int money;虽然他是在Parent类里面定义的,但是Child类继承过来可以对其修改,且可以将修改之后的值存储下来。
值得注意的是,static修饰的变量初始化,必须在类的外面,就好像办理银行卡只能在银行柜台一样,而之后的动作可以在任意一个类里面操作,就如同存钱取钱可以找一个ATM机器一样。

#include <iostream>
#include "string.h"using namespace std;class Parent
{
public:static int money;
public:Parent(int _p){cout << "Parent 构造函数" << endl;money = _p;}void show(){cout << "this is parent  :" << money << "万" << endl;}~Parent(){cout << "Parent析构函数" << endl;}
};int Parent::money = 10;class Child : public Parent
{
public:char *car;
public:Child(int mon, char *n) : Parent(mon) {cout << "Child 构造函数" << endl;car = new char [100];strcpy(car,n);}void show(){cout << "this is child   :" << car << endl;}	~Child(){cout << "child 析构函数" << endl; }
};int main()
{Child ch(100, "Audi");cout << "*************************" << endl;ch.show();ch.Parent::show();return 0;
}

在这里插入图片描述
这里假如你爸爸初始办卡存进去十万,后续你存了90万所以加起来就是100万。第32行代码就如同你爸爸去银行申请银行卡并初始存入10万,这就是static修饰的变量,需要在类外面做初始化,任何一个地方对其修改,都会被记录存储下来 。

继承中对象存储模型
先祭出代码吧,代码是上面关于 鱼 的代码,只是main函数末尾加了三句话,打印出对象的内存首地址。

    cout << "&f    : "<< &f << endl;cout << "&f.s1 : "  << &f.s1 << endl;	cout << "&f.s2 : " << &f.s2 << endl;

在这里插入图片描述
这里可以看出,父类对象首地址在前,子类首地址在后面。内存地址呢,也可以举一个牵强一点的例子,比如你亲戚朋友来你家做客,那么他们首先应该是给你父亲打招呼问好,然后才会谈论你的事情,比如谈恋爱啥的,对吧?这样理解一下,然后就得记住,父类对象地址在前,子类在后。

继承中的类型兼容性原则
子类对象可以当作父类对象使用
接着上面的例子,比如说你继承了你爸爸的工厂,你爸爸可以指挥个人做事情,你当然也有这个权限

#include <iostream>using namespace std;class Parent
{
public:virtual void Work(){cout << "working" << endl;}
};class Child : public Parent
{
public:void fun(){cout << "洗碗" << endl;}
};int main()
{Child c;c.Work();return 0;
}

运行结果会显示work。
基类的引用直接引用派生类 & 基类指针指向派生类
在这里,不得不提及virtual这个关键词了,百度翻译是虚拟,虚拟的 等意思。顾名思义,这个关键词所修饰的函数可以称呼为虚函数,对, 就是那个肾虚的虚。virtual type fun();, 其中virtual算作关键字,type表示函数类型,括号里面可以有参数,这里没写。
这儿也没什么合适的例子了,可能会很晦涩,就算是记住吧,当基类对象指向或者引用派生类对象时候,基类与派生类种必须包含函数原型相同的函数,且基类中函数必须加上virtual修饰。最重要的一点别忘了,继承关系不能丢!话不多说,上代码

#include <iostream>using namespace std;class Parent
{
public://关键字virtual并不能丢virtual void fun() //与派生类Child中fun原型相同{cout << "working" << endl;}
};class Child : public Parent
{
public:void fun(){cout << "洗碗" << endl; //函数原型相同,内容不同}
};int main()
{//父类引用子类对象Child c;Parent &p = c;p.fun();//父类指针指向子类对象Parent *ptr = NULL;ptr = new Child;ptr->fun(); return 0;
}

这里的fun函数,子类父类都有这个相同类型的函数,但是不同的是,父类前面有个virtual修饰。

多继承导致的二义性
先来举个例子说说多继承吧。比如过年的时候,你爷爷给你爸爸压岁钱,也给你大伯压岁钱,然后你爸爸和你大伯又给了你压岁钱,那么问题就是过段时间后,你还会记得你的某几张红票子是你爷爷给你爸爸再给你的,还是你爷爷给了你大伯你大伯再给你的呢?
这样的问题,就叫做多继承导致的二义性问题。话不多说,继续上代码

#include <iostream>using namespace std;class YeYe //爷爷的钞票
{
public :int money;
};class BaBa : public YeYe //给了爸爸一部分
{};class DaBo : public YeYe //给了大伯一部分
{};class My : public BaBa, public DaBo //爸爸和大伯又都给你压岁钱
{};int main()
{My m;m.money;return 0;
}

在这里插入图片描述
由此可以看出,编译阶段就会报错,书上称之为二义性。实质上,这个问题我们可以溯源,就能解决,也不必疑惑,那就是直接把这个钱理解是爷爷给的,爸爸和大伯仅仅是转了下手。对此,c++提出了一个解决方案,即加virtual关键字。

#include <iostream>using namespace std;class YeYe //爷爷的钞票
{
public :int money;
};class BaBa : virtual public YeYe //给了爸爸一部分
{};class DaBo : virtual public YeYe //给了大伯一部分
{};class My : public BaBa, public DaBo //爸爸和大伯又都给你压岁钱
{};int main()
{My m;m.money;return 0;
}

这里的代码比之前的,仅仅是继承时在public前加了个关键字virtual,加上之后,编译的时候便不会报错。这两段代码写的都比较抽象,删繁就简突出了virtual关键字及虚继承的概念。

虚继承时的构造函数
在c++中,规定了由最终派生类来初始化虚基类。接着上面的例子,也就意味着,你爷爷之听你的话,不听你爸爸和你大伯的话,毕竟隔代亲嘛,对吧?

#include <iostream>using namespace std;class YeYe //爷爷的钞票
{
public :int money;
public :YeYe(int a ){money = a;}	
};class BaBa : virtual public YeYe //给了爸爸一部分
{
public :int b;
public :BaBa(int a, int b) : YeYe(a){this->b = b;}
};class DaBo : virtual public YeYe //给了大伯一部分
{
public :int d;
public :DaBo(int a, int b) : YeYe(a){d = b;}
};class My : public BaBa, public DaBo //爸爸和大伯又都给你压岁钱
{
public :int m;
public :My(int a, int b, int c, int d) : YeYe(a), BaBa(10, b), DaBo(20, c){m = d;}void show(){cout << money << endl;cout << b << endl;cout << d << endl;cout << m << endl;}};int main()
{My m(1, 2, 3, 4);m.show();return 0;
}

在派生类My的构造函数中,调用了三个父类的构造函数,可以看出,BaBa给YeYe的初始值是10 ,DaBo给爷爷的赋值是20,而My给YeYe的初始值是1 ,运行后不难发现,
在这里插入图片描述
最终YeYe的money是1,这也就验证了基类的构造函数只能由最终的派生类来对其初始化。

写的有点啰嗦,例子可能也有点牵强,算是写出了自己对于这两天学习继承与派生的一点心得体会吧。

这篇关于浅论继承与派生的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/389118

相关文章

JavaSE——封装、继承和多态

1. 封装 1.1 概念      面向对象程序三大特性:封装、继承、多态 。而类和对象阶段,主要研究的就是封装特性。何为封装呢?简单来说就是套壳屏蔽细节 。     比如:对于电脑这样一个复杂的设备,提供给用户的就只是:开关机、通过键盘输入,显示器, USB 插孔等,让用户来和计算机进行交互,完成日常事务。但实际上:电脑真正工作的却是CPU 、显卡、内存等一些硬件元件。

七、Maven继承和聚合关系、及Maven的仓库及查找顺序

1.继承   2.聚合   3.Maven的仓库及查找顺序

OOP三个基本特征:封装、继承、多态

OOP三个基本特征:封装、继承、多态 C++编程之—面向对象的三个基本特征 默认分类 2008-06-28 21:17:04 阅读12 评论1字号:大中小     面向对象的三个基本特征是:封装、继承、多态。     封装 封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。   封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信

c++ 类的继承详解

在 C++ 中,类的继承是一种面向对象编程(OOP)的特性,允许创建一个新的类(派生类)从一个已有的类(基类)派生。通过继承,派生类可以重用基类的属性和行为,并且可以扩展或修改这些行为。继承是一种代码重用和扩展的机制,使得派生类能够继承基类的特性并添加或修改特性。 1. 继承的基本语法 class Base {// 基类的成员};class Derived : public Base {//

C++ 第8章 继承

继承(Inheritance)是面向对象程序设计中软件重用的关键技术。 8.1 类之间的关系 一个大的应用程序,通常由多个类构成,类与类之间互相协同工作。 class Vehicle{int wheels;double weight;double loading;public:void initialize(int in_wheels, double in_weight);int get

泛型第二课,派生子类、属性类型、方法重写、泛型擦除

子类(实现类) 子类与父类|接口一样使用泛型子类指定具体的类型子类与父类|接口 同时擦除类型子类泛型,父类|接口 擦除错误:不能子类擦除,父类|接口泛型 package com.pkushutong.genericity3;/*** 父类为泛型类* 1、属性* 2、方法* * 要么同时擦除,要么子类大于等于父类的类型* 不能子类擦除,父类泛型* 1、属性类型* 父类中,随父类型定

C++ 菱形继承与虚拟继承的详解与代码示例

在C++中,多重继承虽然强大,但也会带来不少问题。特别是当继承链中出现菱形继承时,容易导致基类的重复实例化。本文将深入讨论菱形继承的问题,并详细解释如何通过虚拟继承来解决它。同时,给出一个简单的代码示例,并逐步解析输出结果。 什么是菱形继承? 菱形继承是指在多重继承中,同一个基类被多个派生类继承,而这些派生类又被另一个类继承,最终形成菱形结构,如下图所示: A/ \B C\ /D

C++_继承详解

继承的概念 继承(inheritance)机制是面向对象程序设计使代码可以复用的重要的手段,它允许程序员在保持原有类特性的基础上进行扩展,增加功能。继承呈现了面向对象程序设计的层次结构,之前我们接触的复用都是函数复用,今天我们所讨论的继承是类设计层次的复用。 子类继承父类的成员后,父类的 成员函数 和 成员变量 都会变成子类的一部分,其中父类的成员函数与子类的成员函数使用的是同一个函数(构造

【C++】C++的输入输出、循环、条件、字符串、数组、类、继承的使用实例

本文介绍C++的基本使用,用一个程序说明的基本运用,当然C++中的指针与运算符的重载这些特色东西还没有涉及,只是把编程中最基本的东西讲述一次, 与《【Python】Windows版本的python开发环境的配置,Helloworld,Python中文问题,输入输出、条件、循环、数组、类》(点击打开链接)是姊妹篇,据说这堆东西出书的话能写很多很多页,上课的话能上大半学期,真是醉了。 以下程