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

C++回顾 Day7

调用子类构造器之前就会调用父类构造器

#include <iostream>
using namespace std;class father
{public:father(){cout << "father()" << endl;}private:int a;
};class son : public father
{public:son(){cout << "son()" << endl;}
};class grandson : public son
{public:grandson(){cout << "grandson()" << endl;} 
};int main()
{father f;cout << "---------------" << endl;son s;cout << "---------------" << endl;grandson g;return 0;
}//结果
//father()
//---------------
//father()
//son()
//---------------
//father()
//son()
//grandson()

同时还要注意,子类只需要管好父类的构造器就可以了

class father
{public:father(int a):a(a){cout << "father()" << endl;}private:int a;
};class son : public father
{public:son():father(4)	//father类没有无参构造所以必须显式调用{cout << "son()" << endl;}
};class grandson : public son
{public:grandson()	//son类有无参构造所以不必显式调用{cout << "grandson()" << endl;} 
};

 

当然了,如果son类通过son(int a):father(a)这种传入参数的方式对father类进行初始化,并且son类不包含其他的默认构造参数,那么grandson类的构造器也必须显式调用son类的构造器

初始化顺序:父类的初始化,类对象的初始化,本类的初始化

遵循一个原则:想要初始化一个类就要先初始化其父类的全部,再初始化其类对象

继承后的拷贝构造器

子类没有自实现拷贝构造器则使用子类的默认拷贝构造器,而子类的默认拷贝构造器会调用父类的拷贝构造器

若实现了则使用自实现的

#include <iostream>
using namespace std;class student
{public:student(string sn,int ia,string sg):name(sn),age(ia),gender(sg){}student(const student &another):name(another.name)//写成参数列表运行快就是因为还未生成this指针就进行了赋值 {this->age = another.age;this->gender = another.gender;}void show(){cout << "name  :" << name << endl;cout << "age   :" << age << endl;cout << "gender:" << gender << endl;}private:string name;int age;string gender;
};class graduate : public student 
{public:graduate(string sn,int ia,string sg,int ss):student(sn,ia,sg),salary(ss){}graduate(const graduate &another):student(another),salary(another.salary)//这里调用了 父类构造器,传入子类用来初始化父类,这是赋值兼容 //赋值兼容:子类的引用或指针能够赋给父类对象的引用或指针 {//this->name = another.name;//这是不合法的,因为name是父类的private成员,对子类是不可见的 }void print(){show();cout << "salary:" << salary << endl;}private:int salary;
};int main()
{student s1("bob",18,"男");s1.show();cout << "----------------" << endl; student s2 = s1;s2.show();cout << "----------------" << endl; graduate g1("dick",22,"女",23000);g1.print();cout << "----------------" << endl; graduate g2 = g1;g2.print();return 0;
}

继承后的赋值重载

子类没有自实现赋值重载则使用子类的默认赋值重载,而子类的默认赋值重载会调用父类的赋值重载

若实现了则使用自实现的

#include <iostream>
using namespace std;class student
{public:student(string sn,int ia,string sg):name(sn),age(ia),gender(sg){}student(const student &another):name(another.name){this->age = another.age;this->gender = another.gender;}student& operator=(const student& another){cout << "student& operator=(const student& another)" << endl;if(this == &another)return *this;this->name = another.name;this->age = another.age;this->gender = another.gender;return *this;}void show(){cout << "name  :" << name << endl;cout << "age   :" << age << endl;cout << "gender:" << gender << endl;}private:string name;int age;string gender;
};class graduate : public student 
{public:graduate(string sn,int ia,string sg,int ss):student(sn,ia,sg),salary(ss){}graduate(const graduate &another):student(another),salary(another.salary){}graduate& operator=(const graduate& another){if(this == &another)return *this;//不写也可以,因为父类赋值重载有自赋值检查,但是加上会使得代码更加健壮 student::operator=(another);//调用了父类的赋值重载,必须加作用域,//不然对于重名的成员,子类会把父类中重名的成员shadow掉//shadow与重载不同,只和参数名有关//同时,这里也发生了一次赋值兼容//这里就会导致递归,程序崩溃 this->salary = another.salary;} void print(){show();cout << "salary:" << salary << endl;}private:int salary;
};int main()
{student s1("bob",18,"男");s1.show();cout << "----------------" << endl; student s2("111",1,"1");s2.show();cout << "----------------" << endl; s2 = s1;s2.show();cout << "----------------" << endl; graduate g1("dick",22,"女",23000);g1.print();cout << "----------------" << endl; graduate g2("222",2,"2",2);g2.print();cout << "----------------" << endl; g2 = g1;g2.print();return 0;
}

注意:

绝不要使得子类中的成员和父类中的成员同名

如果同名发现冲突,要加上作用域(命名空间)

继承后的友元函数

#include <iostream>
using namespace std;class father
{public:father(int _a,int _b):a(_a),b(_b){}friend ostream& operator<<(ostream &os,father &f);private:int a;int b;
};ostream& operator<<(ostream &os,father &f)
{os << f.a << endl << f.b << endl;
}class son : public father
{public:son(int _a,int _b,int _c):father(_a,_b),c(_c){}friend ostream& operator<<(ostream& os,son &s);private:int c; 
};ostream& operator<<(ostream& os,son &s)//只写函数不写具体实现cout << s就不输出了,//因为严格匹配到了这个函数,不再赋值兼容 
{cout << static_cast<father&>(s);//static_cast<father>(s)的话就要//将之前的函数的参数变成const father &f //father::operator<<(cout,s);不对 //友元函数并不是类的一个成员函数,而是与类相关联的一个函数//因此,它不能通过类的作用域解析运算符 :: 直接作为成员函数来调用os << s.c << endl;
}int main()
{father f(1,2);cout << f;son s(3,4,5);//cout << s;//这里会输出3和4,是因为发生了一次赋值兼容 cout << s;return 0;
}

注意:

继承不会继承友元关系;

不能通过域解析运算符 :: 调用父类中的同名的友元函数

析构函数调用的顺序和构造函数相反

先析构子类,再析构对象成员,最后析构父类

对于不同的继承方式

99%使用的都是public继承

不同访问权限的作用

public用来提供接口

protected用来隐藏数据,传承数据

private用来隐藏数据

继承方式总结

public继承了接口,也传承了数据

protected只传承了数据

private既没有继承接口,也没有传承数据

多继承

当一个子类继承自多个父类,而父类之间又有重名的成员,便会出现冗余数据(数据保存了两份),还会给使用者带来不便利(使用前必须加上作用域(类名::))

为了解决这种问题,出现了虚基类和虚继承

就是将这两个父类中共有的东西提取出来放到一个类M里面,然后让这两个父类都虚继承自这个虚基类M。这样数据就只有一份,访问也不会有冲突

#include <iostream>
using namespace std;class M
{public:int m;M(int _m):m(_m){}void show(){cout << m << endl;}
}; class A : virtual public M
{public:A(int a):M(a){}void M_set(int x){m = x;}
};class B : virtual public M
{public:B(int b):M(b){}void M_get(){cout << m << endl;}
};class myclass : public A,public B
{public:myclass(int x):A(2),B(3),M(x){}//这里必须把M的初始化也完成,并且A、B的初始化本质上对m的值没有影响,只是陪跑的void print(){cout << m << endl;}
};int main()
{
//	A a(10);
//	cout << "A a(10);" << endl; 
//	B b(20);
//	cout << "B b(20);" << endl;
//	myclass c(30);
//	cout << "myclass c(30);" << endl;
//	a.M_set(100);
//	cout << "a.M_set(100);" << endl;
//	cout << "b.M_get() = ";
//	b.M_get();
//	cout << "c.print() = ";
//	c.print();
//	c.m = 999;
//	cout << "c.m = 999;" << endl;
//	cout << "c.print() = ";
//	c.print();
//	cout << "b.M_get() = ";
//	b.M_get();myclass t(20);t.show();t.print();t.M_set(10);t.show();t.print();t.m = 999;t.show();t.print();//由于只有M里面存着一份,所以使用A类继承过来的赋值进行赋值还是使用直接赋值都只有一份结果return 0;
}

注意:当同时存在A、B和myclass类时,里面的m是互不干扰的

当只有一个myclass类时,可以理解为将M、A、B的内容都聚合到了一起,只有一份存储


文章转载自:
http://agnosia.wanhuigw.com
http://caecilian.wanhuigw.com
http://chemisorb.wanhuigw.com
http://attired.wanhuigw.com
http://barback.wanhuigw.com
http://ccu.wanhuigw.com
http://bayeux.wanhuigw.com
http://bellyhold.wanhuigw.com
http://chromatid.wanhuigw.com
http://characteristic.wanhuigw.com
http://allhallows.wanhuigw.com
http://accurately.wanhuigw.com
http://aarnet.wanhuigw.com
http://actiyator.wanhuigw.com
http://bowls.wanhuigw.com
http://blinking.wanhuigw.com
http://apprehensively.wanhuigw.com
http://bioelectricity.wanhuigw.com
http://captaincy.wanhuigw.com
http://agnomen.wanhuigw.com
http://allowably.wanhuigw.com
http://burg.wanhuigw.com
http://calorification.wanhuigw.com
http://basil.wanhuigw.com
http://carriageable.wanhuigw.com
http://anticlockwise.wanhuigw.com
http://angular.wanhuigw.com
http://catatonic.wanhuigw.com
http://atrophied.wanhuigw.com
http://bromyrite.wanhuigw.com
http://www.dtcms.com/a/280370.html

相关文章:

  • k8s之Snapshots 详解
  • Linux C IO多路复用
  • 静态补丁脚本 - 修改 libtolua.so
  • Unity音游开发全指南:模板与免费资源高效构建节奏游戏
  • Ubuntu 22.04 安装 mysql-server服务端
  • docker拉取nacos镜像失败
  • golang语法-----标准化输入输出
  • 渗透测试技术_Nessus工具(三):输出报告
  • 构建 Go 可执行文件镜像 | 探索轻量级 Docker 基础镜像(我应该选择哪个 Docker 镜像?)
  • STM32小实验三--让蜂鸣器响起来
  • Pytorch中张量的索引和切片使用详解和代码示例
  • CSS的初步学习
  • 用语音识别芯片驱动TFT屏幕还有链接蓝牙功能?
  • cursor使用mcp连接mysql数据库,url方式
  • java截取视频帧
  • c#进阶之数据结构(字符串篇)----String
  • C++中list各种基本接口的模拟实现
  • 【Java代码审计(2)】MyBatis XML 注入审计
  • 153.在 Vue 3 中使用 OpenLayers + Cesium 实现 2D/3D 地图切换效果
  • java中的接口
  • JavaScript 动态访问嵌套对象属性问题记录
  • HarmonyOS-ArkUI: Web组件加载流程1
  • 暴力破解:攻破系统的终极密钥
  • Rust指针选择
  • 安装带GPU的docker环境
  • 20250715使用荣品RD-RK3588开发板在Android13下接入USB3.0接口的红外相机
  • 【I3D 2024】Deblur-GS: 3D Gaussian Splatting from Camera Motion Blurred Images
  • 记录一条面试sql题目
  • JS中async/await功能介绍和使用演示
  • 普通字符类型和new String有什么区别