继承的笔记


继承的概念

继承是一种使代码能被复用的一种机制。通过继承机制,可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。

继承格式

//  派生类 继承方式 基类
//    ||   ||     ||
class Son:public Dad
{
	public:
	char * identity;//地位
}; 

继承方式和访问限定符

         /--public继承       
       /
继承方式-----protected继承
      \
       \--protected继承

		 /---public访问 
		/
访问限定符 ---protected访问
 		\
 		 \--private访问

继承基类成员访问方式的变化

类成员/继承方式public继承protectedprivate继承
基类的public成员继承到派生类的public继承到派生类的protected继承到派生类的private
基类的protected成员继承到派生类的protected继承到派生的protected继承到派生类的private
基类的private成员在派生类中的不可见在派生类中不可见在派生类中不可见

小结:
1.父类的private成员在任何继承方式下,子类都无法继承
2.除上述外子类能继承到访问限定区域(指public之类)的哪一块,取决于继承方式父类中成员所处区域 哪一个开放程度更小(public>protected>private)
3.子类继承到protected和private的成员在第一次继承中使用没有本质区别,都只能在类内访问,无法在类外访问。但是子类再继承给别的类就能体现区别所在


基类和派生类对象赋值转换

在子类和父类之间,子类能够赋值给父类,这种赋值类似与intint之间的赋值,不会产生类型转换(double与int之间会产生、传参给单参数构造函数也会)
但是父类不能赋值给子类

子类赋值给父类的两种方式:
1.直接赋值

class Dad
{
	public:
	int property;
	char* job; 
};
class Son:public Dad
{
	public:
	char* gf;
};
int main()
{
	Son son;
	Dad d=son;//son类在继承状态下创建对象同时继承Dad类的成员
			  //此时赋值是将除自身成员外来自Dad的成员赋值给d
	Dad *pd=&son;//pd指向son中继承自d的那部分成员

	Dad& rd=son;//rd引用的同样是son继承自d的那部分成员
}

继承中的作用域

这部分内容有个与之相关的词汇叫做隐藏
1.子类虽能继承父类成员并在子类中使用,但他两其实都有独立的作用域
2.当父类和子类有重名成员时,默认调用子类成员
3.在调用时标注上作用域也可以调用父类成员

class Daddy
{
protected:
	string name = "小头爸爸";
};
class Baby:public Daddy
{
public:
	void Print()
	{
		cout << name << endl;
	}
protected:
	string name = "小头儿子";
};

int main()
{
	Baby b;
	b.Print();
}

派生类的默认成员函数

我们都知道默认成员函数不写会自动生成,那么在继承关系中又是怎么样呢

class Person
{
public:
	Person()
	{cout<<"起床"<<endl;}
	Person(const Person& p)
	{cout<<"造娃"<<endl;}
	operator=(const Person& p)
	{cout<<"模仿"<<endl;}
	~Person()
	{cout<<"睡觉"<<endl;}
};
class Student():public Person
{
	//如果在子类不写默认成员函数,系统会调用相对应不写的默认成员函数
	//如果写了,则不会调用父类相对应的默认成员函数
	//如果自己写了也想调用父类的默认成员函数则需要如下列所写
	public:
	Student()
	:Person()
	{}
	Student(const Student& s)
	:Person(const Student& s)
	{}
	operator(const Student& s)
	{
		//因为同名构成隐藏
		Person::operator(s);
	}
	//这里可以不写因为编译器自动完成,为的就是满足  父比子先构造  
	子比父先析构
	~Student()
	{}
};

继承和友元

就提一嘴:
父类的友元子类不能继承


继承和静态成员

静态成员与成员函数一般,多个对象共用一个静态成员


菱形继承

聊到菱形继承首先来看看多继承

class A
{
	public:int _a
};
							   class B:
^							  {
|								public:int _b
|					           };
|							    ^
|							   /
|							  / 
class C:public A,public B
{
	public: int _c
}
//在内存中A(_a),B(_a,_b),C(_a,_b,_c)

再来看看菱形继承

					class A{public:_a};
					^            ^
				/ 				  \
			/						\
	class B:public A
	{int _b}; 
	  ^                             class C:public A
	  |                             {int _c};
      |								  ^
      |								/
   		class D:public B,public C
   		{int _d};
 //A(_a)
 //B(_a,_b)
 //C(_a,_c)
 //D(_a,_b,_c,_d)

在菱形继承中有个最大的问题就是B、C分别继承了_a,那么在D继承B、C后同时也继承到了_a。如果想要使用这个_a那么问题就来了,由于类域的存在,使用_a就会产生二意性。同时,如果A的成员增加的话,D就会数据冗余


菱形虚拟继承

为了解决这个问题,虚拟继承就诞生了

				class A{public:_a};
					^            ^
				/ 				  \
			/						\
	class B:virtual public A
	{int _b}; 
	  ^                             class C:virtual A
	  |                             {int _c};
      |								  ^
      |								/
   		class D:public B,public C
   		{int _d};

通过虚拟继承的_a ,它就类似静态成员,多个类共用一个变量,这样不仅解决了二意性还解决了数据冗余。
但同样虚拟继承继承了类似于name这样的变量就不太合适了,所以酌情使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值