当前位置: 首页 > news >正文

基类和派生类的赋值对象转换、派生类与基类成员的函数隐藏、派生类中的默认成员函数、继承与友元、继承与静态成员函数、菱形继承、菱形虚拟继承等的介绍

文章目录

  • 前言
  • 一、基类和派生类的赋值对象转换
  • 二、派生类与基类成员的函数隐藏
  • 三、派生类中的默认成员函数
  • 四、继承与友元
  • 五、 继承与静态成员函数
  • 六、菱形继承
  • 七、菱形虚拟继承
  • 总结


前言

基类和派生类的赋值对象转换、派生类与基类成员的函数隐藏、派生类中的默认成员函数、继承与友元、继承与静态成员函数、菱形继承、菱形虚拟继承等的介绍


一、基类和派生类的赋值对象转换

派生类可以赋值给基类,因为会是使用切片、切割的方式将派生类中基类所拥有的成员赋值给基类
基类不可以直接赋值给派生类

在这里插入图片描述

#include <iostream>
#include <string>
using namespace std;class Person
{
public:string _name;string _sex;int _age;
};class Student : public Person
{
public:int _No;
};
int main()
{Student s;s._name = "zhangsan";s._sex = "nan";s._age = 18;s._No = 999;Person p;p = s;return 0;
}

在这里插入图片描述

二、派生类与基类成员的函数隐藏

当派生类中的成员函数与基类中的成员函数同名时,就会默认隐藏基类中的成员函数,只能访问到派生类的成员函数,若需要访问基类中的成员函数,需要加类的访问限定符。

#include <iostream>
using namespace std;class Person
{
public:void fun(){cout << "name:" << _name << endl;}protected:string _name = "peter";int _num = 100;
};class Student : public Person
{
public:void fun(int i){// 派生类找成员变量的顺序,默认从局部域开始找,若没有去自己的类中找,// 若没有再去基类中找,最后再去全局域中找,没找到报错//int _num = 0;cout << "num:" << _num << " i:" << i << endl;cout << "Person::num:" << Person::_num << endl;}protected:int _num = 999;
};
int main()
{Student s;s.fun(1);s.Person::fun();return 0;
}

三、派生类中的默认成员函数

  • 派生类中的构造函数,会默认调用基类的默认构造函数,若基类中没有默认构造函数,则需要手动调用。

  • 派生类中的拷贝构造,在调用基类的拷贝构造函数时,只要传入派生类对象即可,因为派生类会自动切片赋值给基类

  • 派生类中的赋值运算符重载函数,与基类中的赋值运算符重载函数名相同,会自动隐藏,在调用基类中的赋值运算符重载时,要加类访问限定符调用基类的赋值运算符重载函数。

  • 派生类中的析构函数,在析构函数调用结束时会自动调用基类中的析构函数,因为必须先析构派生类,再析构基类(防止析构完基类,但再次用到基类的成员)

// 派生类的默认成员函数
#include <iostream>
using namespace std;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){if (this != &p){_name = p._name;}return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name;
};class Student : public Person
{
public:// 派生类的构造函数会在初始化列表中先调用基类的默认构造函数,在对自己的成员变量初始化// 如果基类中没有默认构造函数,需要在派生类的初始化列表调用基类的构造函数// 派生类继承基类,基类成员的声明一定是在派生类中的,所以初始列表一般应先初始化基类成员,与声明保持一致Student(const char* name = "zhangsan", int num = 99):Person(name),_num(num){}Student(const Student& s):Person(s),_num(s._num){}Student& operator=(const Student& s){if (this != &s){// 直接写operator=会调用派生类的赋值运算符重载// 此处应该调用基类的赋值运算符重载,应该加类域Person::operator=(s);_num = s._num;}return *this;}~Student(){}
protected:int _num;
};int main()
{Student s1("knowledge", 100);Student s2(s1);Student s3;s3 = s2;return 0;
}

在这里插入图片描述

在这里插入图片描述

四、继承与友元

友元关系不能继承

五、 继承与静态成员函数

基类定义了static静态成员,则整个继承体系里面只有一个这样的成员。无论派生出多少个子类,都只有一个static成员实例 。

所以,我们可以计算一个基类以及它的派生列共实例化了多少个对象。

因为每一个派生类构造时都会调用基类的默认构造,所以我们用静态成员变量在基类的默认构造中计数

#include <iostream>
#include <string>
using namespace std;
class Person
{
public:Person() { ++_count; }
protected:string _name;
public:static int _count;
};
int Person::_count = 0;class Student : public Person
{
protected:int _num;
};class Teacher : public Person
{
protected:int _id;
};
int main()
{Person p;Student s1;Student s2;Teacher t;cout << p._count << endl; // 4return 0;
}

在这里插入图片描述

六、菱形继承

#include<iostream>
#include <string>
using namespace std;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:int _age;
};int main()
{Assistant a;// 二义性的问题,_name指向不明确//a._name = "zhangsan";// 可以解决二义性的问题,但是无法解决数据冗余的问题a.Student::_name = "zhang";a.Teacher::_name = "Mr.zhang";return 0;
}

在这里插入图片描述

七、菱形虚拟继承

在腰部的类的继承方式前面加 virtual

虚拟继承会改变类对象模型的结构,比如: D会改变B和C的结构,B中除了存储_b外,还存除了,当前位置到A的偏移量。有了偏移量可以让每个类都有很好的访问方式

#include<iostream>
#include <string>
using namespace std;class A
{
public:int _a;
};class B : virtual public A
{
public:int _b;
};class C : virtual public A
{
public:int _c;
};class D : public B, public C
{
public:int _d;
};int main()
{D d;d._a = 2;d._b = 3;d._c = 4;d._d = 5;return 0;
}

在这里插入图片描述


总结

基类和派生类的赋值对象转换、派生类与基类成员的函数隐藏、派生类中的默认成员函数、继承与友元、继承与静态成员函数、菱形继承、菱形虚拟继承等的介绍


http://www.mrgr.cn/news/35032.html

相关文章:

  • Java:Object操作
  • Linux Shell: 使用 Expect 自动化 SCP 和 SSH 连接的 Shell 脚本详解
  • 软件安全测评的必要性,安全测评有必要找第三方软件检测机构吗?
  • ECharts的特点
  • JMeter与大模型融合应用之JMeter菜单栏中切入大模型交互详解
  • 什么软件可以同声传译?5款高效沟通的翻译软件速速收藏
  • 低场核磁共振成像系统MRI的成像优势特点
  • 车辆合格证识别接口-汽车管理智能化-python示例
  • 外包功能测试干了4年,技术退步太明显了。。。。。
  • 【Docker】在 CentOS 上安装 Docker 的完整指南
  • python类的call方法与init方法
  • 搜索引擎onesearch3实现解释和升级到Elasticsearch v8系列(二)-索引
  • 嵌入式必备技能
  • AI推介-大语言模型LLMs之RAG(检索增强生成)论文速览(arXiv方向):2024.07.20-2024.08.15
  • 神经网络(二):卷积神经网络
  • visual studio 调试技巧
  • 如何进行“服务器内部错误”的诊断 | OceanBase诊断案例
  • 闰年判断-C语言
  • 使用Nginx反向代理为OneAPI配置https访问
  • LDRA Testbed(TBrun)软件单元测试_常见问题及处理