首页 > 编程语言 >C++继承

C++继承

时间:2024-11-07 15:47:36浏览次数:6  
标签:name 继承 基类 C++ Person 派生类 public

文章目录

一、继承的概念和定义

1、继承的概念

继承(inheritance)机制是⾯向对象程序设计使代码可以复⽤的最重要的⼿段,它允许我们在保持原有类特性的基础上进⾏扩展,增加⽅法(成员函数)和属性(成员变量),这样产⽣新的类,称派⽣类。继承呈现了⾯向对象程序设计的层次结构,体现了由简单到复杂的认知过程。以前我们接触的函数层次的复⽤,继承是类设计层次的复⽤。

2、继承的定义
class Person
{
public:
		void identity()
	{
		cout << "void identity()" << _name << endl;
	}
protected:
	string _name;
	string _address;
	string _tel;
	int _age = 18;
};

class Student : public Person
{
public:
	void study()
	{
		
	}
protected:
	int _stuid;
};

class Teacher : public Person
{
public:

	void teaching()
	{
	
	}
protected:
	string title;
};

Person类称为父类也叫基类,Teacher和Student类称为子类也叫派生类。

在这里插入图片描述

3、继承基类成员访问方式的变化
类成员/继承方式publicprotected继承private继承
基类的publice成员派生类的public成员派生类的protected成员派生类的private成员
基类的protected成员派生类的protected成员派生类的protected成员派生类的private成员
基类的private成员在派生类不可见在派生类中不可见在派生类中不可见

在这里插入图片描述
在这里插入图片描述

二、基类和派生类之间的转换

在这里插入图片描述

class Person
{
protected:
	string _name; // 姓名
	string _sex; // 性别
public:
	int _age = 18; // 年龄
};

class Student : public Person
{
public:
	int _No; // 学号
};

int main()
{
	Student sobj;
	// 赋值兼容转换,特殊处理
	// 1.派生类对象可以赋值给基类的指针/引用
	Person* pp = &sobj;
	Person& rp = sobj;
	return 0;
}
  • 赋值兼容转换:就相当于把派生类直接赋值给基类中间不会产生临时对象

在这里插入图片描述

三、继承中的作用域

1、隐藏规则

在这里插入图片描述

class Person
{
protected:
   string _name = "张三";//姓名
   int _num = 4209999;//身份证
};

class Student : public Person
{
public:
   void Print()
   {
   	cout << "姓名:" << _name << endl;
   	cout << "学号:" << _num << endl;
   	cout << "身份证号:" << Person::_num << endl;
   }
protected:
   int _num = 16;//学号
};

基类和派生类成员同名,优先访问派生类中的成员,如果想访问基类成员需要指定类域显示调用

四、派生类的默认成员函数

1、常见默认成员函数
  • 构造函数、析构函数、拷贝构造、赋值运算符重载、取地址运算符重载(const对象和普通对象)

在这里插入图片描述

class Person
{
public:
	Person(const char* name)
		: _name(name)
	{
		cout << "Person()" << endl;
	}

	Person(const Person& p)
		: _name(p._name)
	{
		cout << "Person(const Person& p)" << endl;
	}

	Person& operator=(const Person& p)
	{
		cout << "Person operator=(const Person& p)" << endl;
		if (this != &p)
			_name = p._name;

		return *this;
	}

	// destructor()
	~Person()
	{
		cout << "~Person()" << endl;
	}

protected:
	string _name; // 姓名
};

class Student : public Person
{
public:

	Student(int num = 18, const char* name = "张三", const char* address = "武汉")
		:_num(num)
		, _address(address)
		, Person(name)//把父类当成整体初始化
	{
		cout << "Student()" << endl;
	}

	Student(const Student& s)
		:Person(s)
		, _num(s._num)
		,_address(s._address)
	{
		cout << "Student(const Student& s)" << endl;
	}

	Student& operator = (const Student& s)
	{
		if (this != &s)
		{
			_num = s._num;
			_address = s._address;
			Person::operator=(s);
			cout << "Student& operator = (const Student& s)" << endl;
		}

		return *this;
	}

	~Student()
	{
		cout << "~Student()" << endl; 
	}

protected:
	int _num; //学号
	string _address;

};
  • 初始列表中先定义的先声明,在派生类父类是最先声明的也是最先初始化的。
  • 析构后定义的先析构
2、实现一个不能被继承的类

⽅法1:基类的构造函数私有,派⽣类的构成必须调⽤基类的构造函数,但是基类的构成函数私有化以后,派⽣类看不⻅就不能调⽤了,那么派⽣类就⽆法实例化出对象。

⽅法2:C++11新增了⼀个final关键字,final修饰的基类,派⽣类就不能继承了。

class Base final//C++ 11的方法
{
public:
	void func5() { cout << "Base::func5" << endl; }
protected:
	int a = 1;
private:
	// C++98的方法
	/*Base()
	{}*/
};

五、继承与友元

友元关系不能继承,也就是说基类友元不能访问派⽣类私有和保护成员 。

六、继承与静态成员变量

基类定义了static静态成员,则整个继承体系⾥⾯只有⼀个这样的成员。⽆论派⽣出多少个派⽣类,都只有⼀个static成员实例。

七、多继承和菱形继承

1、继承模型
  • 单继承:⼀个派⽣类只有⼀个直接基类时称这个继承关系为单继承。
  • 多继承:⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承,多继承对象在内存中的模型是,先继承的基类在前⾯,后⾯继承的基类在后⾯,派⽣类成员在放到最后⾯。
  • 菱形继承:菱形继承是多继承的⼀种特殊情况。菱形继承的问题,从下⾯的对象成员模型构造,可以看出菱形继承有数据冗余和⼆义性的问题,在Assistant的对象中Person成员会有两份。⽀持多继承就⼀定会有菱形继承,像Java就直接不⽀持多继承,规避掉了这⾥的问题,所以实践中我们也是不建议设计出菱形继承这样的模型的。
class Person
{
public:
	string _name; // 姓名
};

class Student :public Person
{
protected:
	int _num; //学号
};

class Teacher : public Person
{
protected:
	int _id; // 职工编号
};

class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};

int main()
{
	// 编译报错:error C2385: 对“_name”的访问不明确
	Assistant a;
	//a._name = "peter";

	// 需要显示指定访问哪个基类的成员可以解决二义性问题,但是数据冗余问题无法解决
	a.Student::_name = "xxx";
	a.Teacher::_name = "yyy";

	return 0;
}

在这里插入图片描述
在这里插入图片描述

3、虚继承(关键词virtual)

很多⼈说C++语法复杂,其实多继承就是⼀个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂,性能也会有⼀些损失,所以最好不要设计出菱形继承。多继承可以认为是C++的缺陷之⼀,后来的⼀些编程语⾔都没有多继承,如Java。

class Person
{
public:
	string _name; // 姓名
};

class Student : virtual public Person
{
protected:
	int _num; //学号
};

class Teacher : virtual public Person
{
protected:
	int _id; // 职工编号
};

class Assistant : public Student, public Teacher
{
protected:
	string _majorCourse; // 主修课程
};

int main()
{
	// 编译报错:error C2385: 对“_name”的访问不明确
	Assistant a;
	a._name = "peter";

	// 需要显示指定访问哪个基类的成员可以解决二义性问题,但是数据冗余问题无法解决
	a.Student::_name = "xxx";
	a.Teacher::_name = "yyy";

	return 0;
}

在存在二义性的继承前面加virtual

八、继承和组合

  • public继承是⼀种is-a的关系。也就是说每个派⽣类对象都是⼀个基类对象。

  • 组合是⼀种has-a的关系。假设B组合了A,每个B对象中都有⼀个A对象。

  • 继承允许你根据基类的实现来定义派⽣类的实现。这种通过⽣成派⽣类的复⽤通常被称为⽩箱复⽤(white-box reuse)。术语“⽩箱”是相对可视性⽽⾔:在继承⽅式中,基类的内部细节对派⽣类可⻅。继承⼀定程度破坏了基类的封装,基类的改变,对派⽣类有很⼤的影响。派⽣类和基类间的依赖关系很强,耦合度⾼。

  • 对象组合是类继承之外的另⼀种复⽤选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接⼝。这种复⽤⻛格被称为⿊箱复⽤(black-boxreuse),因为对象的内部细节是不可⻅的。对象只以“⿊箱”的形式出现。组合类之间没有很强的依赖关系,耦合度低。优先使⽤对象组合有助于你保持每个类被封装。

  • 优先使⽤组合,⽽不是继承。实际尽量多去⽤组合,组合的耦合度低,代码维护性好。不过也不太那么绝对,类之间的关系就适合继承(is-a)那就⽤继承,另外要实现多态,也必须要继承。类之间的关系既适合⽤继承(is-a)也适合组合(has-a),就⽤组合。

标签:name,继承,基类,C++,Person,派生类,public
From: https://blog.csdn.net/2401_83305953/article/details/143401729

相关文章

  • C++ 的前世今生:从“小兄弟”到编程大佬
    当你听到C++这个名字,可能会有点好奇:为什么名字里有个“++”?其实,这个“++”是C++编程中的一个符号,意思是“加一”,也可以理解为“进化版”。C++的名字暗示了它比C语言更加强大、功能更多。那么,这个编程语言是怎么来的?又有什么特别之处呢?让我们用大白话来聊聊C++的历......
  • 使用C++和QT开发应用程序入门以及开发实例分享
    目录1、搭建开发环境(VS2010和QT4.8.2)2、创建一个QT窗口3、在QT窗口中添加子窗口4、QT界面布局5、QT信号(SIGNAL)和槽(SLOT)6、最后C++软件异常排查从入门到精通系列教程(专栏文章列表,欢迎订阅,持续更新...)https://blog.csdn.net/chenlycly/article/details/125529931C/C++实......
  • C++ 的“百变魔法”:搞懂基本数据类型和变量
    编程世界里,数据就像材料,而基本数据类型就决定了这些材料能做什么。每种数据类型都有它自己的“特长”,我们可以用它们来处理不同的信息。今天,我们就来看看C++里最常见的几种基本数据类型:int,char,float,double,bool,以及如何用变量来存储这些数据。什么是数据类型?简单......
  • CUDA开始的GPU编程 - 第四章:C++封装GPU上的数组
    第四章:C++封装GPU上的数组std::vector的秘密:第二模板参数**你知道吗?**std::vector作为模板类,其实有两个模板参数:std::vector<T,AllocatorT>那为什么我们平时只用了std::vector呢?因为第二个参数默认是std::allocator。也就是std::vector等价于std::vector<T,s......
  • 应届生必看!23 个高质量 C++ 项目推荐,校招简历秒加分
    大家好,我是小康。最近,不少同学私信我,临近毕业忙着找工作,想问有没有推荐的C++项目,既能练手又能让简历更出彩。我也想起自己当年毕业时同样的焦虑,知道作为C++后端开发的求职者,有几个实际且吸引人的项目,能在面试时为自己增添不少分量。今天就结合我的经验,给大家推荐几个项目,都......
  • C++ explicit关键字
    C++explicit关键字explicit关键字是什么explicit是C++中的一个关键字,它用来修饰只有一个参数的类构造函数,以表明该构造函数是显式的,而非隐式的。当使用explicit修饰构造函数时,它将禁止类对象之间的隐式转换,以及禁止隐式调用拷贝构造函数。这能这么说,大家不太好理解,既......
  • c++ Kruskal 最小生成树 (MST) 算法(Kruskal’s Minimum Spanning Tree (MST) Algorith
            对于加权、连通、无向图,最小生成树(MST)或最小权重生成树是权重小于或等于其他所有生成树权重的生成树。Kruskal算法简介:        在这里,我们将讨论Kruskal算法来查找给定加权图的MST。         在Kruskal算法中,按升序对给定图的所有......
  • C++ ftp上传文件
     目录结构:ftpdemo/include/elapse.h1/*************************************************2Copyright(C),2019-2029,GuideTech.Co.,Ltd.3Filename:elapse.h4Author:henry5Version:V1.0.0.06Date:202410087Description:计算函数运行时间......
  • 【C++篇】在秩序与混沌的交响乐中: STL之map容器的哲学探寻
    文章目录C++`map`容器详解:高效存储与快速查找前言第一章:C++`map`的概念1.1`map`的定义1.2`map`的特点第二章:`map`的构造方法2.1常见构造函数2.1.1示例:不同构造方法2.2相关文档第三章:`map`的常用操作3.1插入操作详解3.1.1使用`insert()`插入元素3.1.2......
  • c++ map用法
    std::map 是C++标准库中的一个关联容器,用于存储键值对(key-valuepairs)。它的特性和用途如下:键值对存储:std::map 是一种关联容器,每个元素都由一个唯一的键(key)和一个值(value)组成。键用于标识数据的唯一性,值是与键相关联的数据。std::map<int,std::string>myMap;myMap[1]=......