C++继承

一.继承概念

继承就是在原有成员基础上添加特有的成员形成派生类

1.继承的作用

目的:代码重用提高执行效率

关键词:基类(父类)、派生类(子类)

意义:子类拥有父类的成员、子类拥有父类没有的特性、子类是一种特殊的父类(子类可以当做父类使用)

2.继承注意点

  • 不能继承父类的构造析构和友元函数
  • 子类拥有父类所有成员属性和行为
  • 一个类可以有多个基类,也可以有多个派生类

3.继承

派生类成员包括两大部分:一是从基类继承下来的成员(与基类拥有共同的特性)、二是本身独有的特性

格式:

class B:public A{             //类B公有继承类A

};

二、继承分类

1.单一继承

1)公有继承

公有继承下来权限不变。公有即公有、保护即保护、私有即私有

2)保护继承

保护继承:父类原先公有、保护权限在子类中变成保护权限。------类内可以访问,类外不可以访问。

                父类原先私有权限在子类中为私有权限。------类内类外都不可以访问

3)私有继承

私有继承:父类原先公有、保护权限在子类中变成私有权限。------类内可以访问,类外不可以访问。

                  父类原先私有权限在子类中为私有权限。------类内类外都不可以访问

2.派生类成员权限恢复操作

适用范围:对于private和protected继承方式,基类的public成员变成private或者protected。

using 基类名::成员名(行为也只写名,不加括号)

注意:访问声明仅能将继承的成员恢复到原来的访问权限

class base{
public:
	base():A(10),B(20),C(30)
	{
		
	}
	int A;
	void fun()
	{
		cout<<"fun"<<endl;
	}
protected:
	int B;
private:
	int C;
};
//派生类
class home:protected base{
public:
	//using 基类名::成员名;//成员函数名后不要加上()
	using base::A;
	using base::fun;	//
	void function()
	{
		fun();
		cout <<A<<endl; 
	}
	
};

3.继承构造与析构顺序

子类实例化:

4.继承同名函数处理

无论静态成员还是非静态成员。

访问子类:直接加"."访问

访问父类:加"::"作用域

5.基类与派生类之间类型转换

  • 派生类对象可以隐式转换为基类对象
#include<iostream>
using namespace std;


class Pason
{
public:
	void test()
	{
		cout<<"父类"<<endl;
	}
private:
};
class pason:public Pason{
public:
	void test()
	{
		cout<<"子类"<<endl;
	}
private:
};
void Test(Pason a)
{
	a.test();
}

int main()
{
	pason aa;
	Test(aa);
}

  • 派生类的对象可以初始化基类的引用;
int main()
{
	pason aa;//派生类
	Pason &bb = aa; //基类
	bb.test();//基类

}
  • 派生类的指针可以隐含转换为基类的指针(注意子类析构问题)
int main()
{
	pason aa;//派生类
	Pason *bb = new pason; //基类
	bb->test();//基类

}

2.多继承

class 子类名:public A,public B,public C{};

注意问题:要加作用域区分同名函数,多继承一般不推荐使用

多继承情况下,先构造父类(从左到右),在构造子类。先析构子类,在析构父类。

3.菱形继承

菱形继承: A B同时继承N,他们有共性成员aa,当C多继承A和B,aa也被继承下来。此时调用aa不知道是A.aa还是B.aa  ----- 二义性

解决办法:虚继承(将共同的基类设置为虚基类)

虚基表:用来存放虚基类的偏移量,以NULL结尾

使用方法:

class N{
public:
	void Display_N()
	{
		cout<<"N::name:"<<&name<<endl;
		cout<<"N::car:"<<&car<<endl;
		cout<<"N::lover:"<<&lover<<endl;
	}
	int name;
};

class A:virtual public N{
public:
	void Display_A()
	{
		cout<<"A::name:"<<&name<<endl;
		cout<<"A::car:"<<&car<<endl;
		cout<<"A::lover:"<<&lover<<endl;
	}
};

class B:virtual public N{
public:
	void Display_B()
	{
		cout<<"B::name:"<<&name<<endl;
		cout<<"B::car:"<<&car<<endl;
		cout<<"B::lover:"<<&lover<<endl;
	}
};
class C:public A,public B{
public:

protected:
	
};

三.注意点

1.多继承构造顺序

所有的虚基类按照他们继承的顺序构造---->所有的非虚基类按照他们继承的顺序构造---->派生类内所有的子对象按照他们定义的顺序构造---->派生类自己的构造

#include <iostream>

using namespace std;
class A{
public:
	A()
	{
		cout<<"A的构造函数"<<endl;
	}
};
class B{
public:
	B()
	{
		cout<<"B的构造函数"<<endl;
	}
};
class C{
public:
	C()
	{
		cout<<"C的构造函数"<<endl;
	}
};
class D: public A,virtual public B{
public:
	C cc;                         //子对象
	D()
	{
		cout<<"D的构造函数"<<endl;
	}
};
int main()
{
	D dd;
}

2.在派生类的构造函数成员初始化列表可以为

调用基类的构造函数

派生类中子对象初始化

class D: public C{      //派生类
public:
	B  b; 
	D():b(10)//派生类子对象初始化
	{
		cout<<"D的构造函数"<<endl;
	}
};

派生类中一般数据成员的初始化

调用基类的子对象的初始化会出错,应该在基类中进行初始化

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值