C++继承 day7

C++继承

基础概念

  • 继承:通常子类中不会产生新的属性或者行为
    • 子类
    • 父类
  • 派生:派生类当中会产生新的属性或者行为
    • 派生类
    • 基类
  • C++继承和派生语法一样
//继承
class 父类
{
	public:
	protected:
};
class 子类名:继承方式 父类名
{
	public:
	protected:
}
//派生
class 基类
{
	public:
	protected:
}
class 派生类名:继承方式 基类
{
	public:
	protected:
}

C++继承要点

  • 权限问题
    • 权限限定词只会加深父类中属性在子类中呈现
    • 父类中的私有属性子类不能直接访问
    • 继承具有传递性,继承的属性会一直存在,继承不适合写太多层数
继承方式public继承protected继承private继承
父类publicpublicprotectedprivate
父类protectedprotectedprotectedprivate
父类private不可访问不可访问不可访问
  • 代码验证
#include <iostream>
//父类
class student 
{
public:
	int age;
	std::string getName()//提供一个共有继承接口
	{
		return name;
	}
protected:
	int ID;
private:
	std::string name;
};
//共有继承
class xiaogua :public student
{
public:
	void print()
	{
		std::cout << age << std::endl;//父类中的共有属性
		std::cout << ID << std::endl;//父类中的保护属性
		//std::cout << name << std::endl;//父类中的私有属性不可访问
		std::cout << getName() << std::endl;//通过一个共有接口访问私有属性
	}
protected:

private:


};
//保护继承 在子类中的,父类中的公共属性会变成保护属性
class xiaoguagua :protected student
{
public:

protected:

private:


};
//私有继承,父类中的所有的属性都会在子类中变成私有属性,但是任然可以访问父类共有属性
class xiaoguaguagua :private student
{
public:
	void print()
	{
		std::cout << age << std::endl;//父类中的共有属性
		std::cout << ID << std::endl;//父类中的保护属性
		//std::cout << name << std::endl;//父类中的私有属性不可访问
		std::cout << getName() << std::endl;//通过一个共有接口访问私有属性
	}
protected:
	
private:


};

int main()
{
	xiaogua boy1;
	boy1.age = 21;
	xiaoguagua boy2;//最低权限就是protected属性
	//boy2.age = 21; 不可访问因为变成了保护属性,这就是权限限定词只会加深父类中属性在子类中呈现
	return 0;
}
  • 构造函数语法:必须要采用初始化参数列表方式调用父类的构造函数初始化父类属性
    • 为了子类能够写无参构造函数.父类构造函数必须存在无参调用形态
    • 一般情况子类的构造函数传参一般包括自身和父类中
    • 在子类构造函数中最好都采用函数缺省的方法进行构造,可以带来很多方便性,以及不必要的问题
  • 代码验证
#include <iostream>
#include<string>
//父类
class student 
{
public:
	//子类存在无参的调用形态关键点在于父类构造函数存在无参调用形式,所以采用缺省方法就比较方便
	student(std::string name = "", int age = 0) :name(name), age(age) {}
protected:
	int age;
	std::string name;
};
//共有继承
class xiaogua :public student
{
public:
	xiaogua(std::string name = "子类默认", int age = 0, int num = 0) :student(name, age), num(num) {}
	void print()
	{
		std::cout << name << "\t" << age << "\t" << num << std::endl;
	}
protected:
	int num;
};
class xiaoshagua :public xiaogua
{
public:
	//孙子类不需要去管祖父类,只需要调用父类构造函数即可
	xiaoshagua(std::string name = "孙子类默认", int age = 0, int num = 0, int xg = 0) :xiaogua(name, age, num), xg(xg) {}
	void print()
	{
		std::cout << name << "\t" << age << "\t" << num << "\t" << xg << std::endl;
	}
protected:
	int xg;
};
int main()
{
	xiaogua boy1("小瓜", 20, 100);
	boy1.print();
	xiaogua boy2;
	boy2.print();
	xiaoshagua boy3;
	boy3.print();
	xiaoshagua boy4("孙子瓜",21,100,200);
	boy4.print();
	return 0;
}
  • 运行结果
    在这里插入图片描述

C++多继承

  • 多继承:两个即以上的父类称之为多继承
  • 构造写法
  • 构造和析构顺序问题:和继承顺序有关,和初始化参数列表无任何关系
#include <iostream>
#include<string>
class father 
{
public:
	father(std::string f_xing = "", std::string f_ming = "") :f_xing(f_xing), f_ming(f_ming) {
		std::cout << "父:" << f_xing << f_ming << std::endl;
	}
protected:
	std::string f_xing;
	std::string f_ming;
};
class mom
{
public:
	mom(std::string m_xing = "", std::string m_ming = "") :m_xing(m_xing), m_ming(m_ming) {
		std::cout << "母:" << m_xing << m_ming << std::endl;
	}
protected:
	std::string m_xing;
	std::string m_ming;
};
class xiaogua :public father,public mom//构造顺序跟继承顺序有关,这里就是先继承的父后继承的母
{
public:
	xiaogua(std::string m_xing = "", std::string m_ming = "", std::string f_xing = "", std::string f_ming = "")
		:mom(m_xing,m_ming),father(f_xing,f_ming)
	{
		this->xg_xing = m_xing + f_xing;
		this->xg_ming = m_ming + f_ming;
	}
	void print()
	{
		std::cout << "子:" << xg_xing << xg_ming << std::endl;
	}
protected:
	std::string xg_xing;
	std::string xg_ming;
};
int main()
{
	xiaogua boy("上", "小", "子", "瓜");
	boy.print();
	return 0;
}

在这里插入图片描述

  • 虚继承(菱形继承):用virtual修饰的继承
  • 产生虚继承的原因是因为二义性问题
    在这里插入图片描述
  • 虚继承一定要调用祖父类的构造函数
#include <iostream>
class A
{
public:
	A(int a) :a(a) {}
		int a;
};
class B :virtual public A
{
public:
	B(int a) :A(a) {
		std::cout << "B(a):" << std::endl;
	}
};
class C : virtual public A
{
public:
	C(int a) :A(a) {
		std::cout << "C(a):" << std::endl;
	}
};
class D :public B, public C
{
public:
	//虚继承一定要调用祖父类的构造函数
	D(int a) :B(1), C(2),A(a){
		std::cout << "D(a)" << std::endl;
	}
	void print()
	{
		//只存在一个,所有的a都是同一个a,并且只由祖父类的构造函数决定
		std::cout << A::a << std::endl;
		std::cout << B::a << std::endl;
		std::cout << C::a << std::endl;
		std::cout << D::a << std::endl;
	}
};
int main()
{
	D d(3);
	d.print();
	return 0;
}
  • 运行结果
    在这里插入图片描述

C++继承中的同名问题

  • 同名遵循原则:
    • 类中类外遵循就近原则
    • 非正常的对象指针初始化,无virtual看指针类型,存在多态看对象
    • 父类指针被子类对象初始化,看对象指针
  • 想要强制的调用父类或者子类中的函数,可以采用类名限定的方式,这种调用方式就不存在多态了,不常见
#include <iostream>
#include <string>
class MM
{
public:
	MM(std::string name) :name(name) {}
	void print()
	{
		std::cout << "MM" << std::endl;
	}
	void printMM()
	{
		std::cout << "printMM" << std::endl;
	}
protected:
	std::string name;
};
class Boy :public MM
{
public:
	Boy(std::string name) :name(name), MM("mm")
	{

	}
	void print()
	{
		std::cout << "Boy" << std::endl;
	}
	void printData()
	{
		std::cout << "------------" << std::endl;
		//就近原则
		print();			//调用Boy
		MM::print();		//调用父类中的
		std::cout << "------------" << std::endl;
	}
protected:
	std::string name;
};

int main()
{
	//正常初始化情况
	Boy boy("boy");
	boy.printData();
	//就近原则
	boy.print();
	boy.MM::print();//强制性调用父类里面的函数
	boy.Boy::print();
	Boy* pBoy = new Boy("Son");
	pBoy->print();
	MM* pMM = new MM("MM");
	pMM->print();
	//非正常初始化情况
	MM* pGirl = new Boy("Son");
	//没virtual 看指针类型
	pGirl->print();
	//错误
	//Boy* pSon = new MM("Girl");
	MM mm("girl");
	//强上
	Boy* pSon = (Boy*)(&mm);
	std::cout << "强制转换的,还是看指针类型: ";
	pSon->print();
	//子类没有,父类有的,被继承了
	pSon->printMM();
	//调用子类中父类没有的
	pSon->printData();

	return 0;
}
  • 运行结果
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值