继承小结

 

     继承是复用代码的重要手段也为动态多态提供了平台

     定义格式:

                  

一、 继承关系

    基类(父类)   

    派生类(子类)

   派生类对象模型如图:

                                              

    


     

   类 缺少继承权限:默认权限为private继承

   结构体缺少继承权限:默认权限为public继承

   

  

#include <iostream>

using namespace std;
class Base
{
public:
	Base(int a = 1)
		:_b(a)
	{}
	~Base()
	{
		cout << "Base()" << endl;
	}
	int _B;
private:
	int _b;
};
class Derive :public Base
{
public:
	Derive(int a)
		:Base(a)
		,_d(a)
	{}
	~Derive()
	{
		cout << "Derive()" << endl;
	}
private:
	int _d;

};
class D :protected Base
{
public:
	D(int a)
		:Base(a)
		, _D(a)
	{}
	~D()
	{
		cout << "D()" << endl;
	}
	
private:
	int _D;
};
class DD :private Base
{
public:
	DD(int a)
		:Base(a)
		, _DD(a)
	{}
	~DD()
	{
		cout << "DD()" << endl;
	}
private:
	int _DD;
};
int main()
{
	Derive a(1);
	D b(1);
	DD c(1);
	/*Base b(1);*/
	a._B = 10;
	b._B = 1;
	c._B = 1;
	system("pause");
	return 0;
}

   二、

          派生类构造函数的初始化链表先完成基类对象构造(调用基类的构造函数)最后构造派生类自己特有的成员

                派生类先调用自己的析构函数最后调用基类析构函数

         1、基类没有缺省构造函数,派生类必须要在初始化列表中显式给出基类名和参数列表。
         2、基类没有定义构造函数,则派生类也可以不用定义,全部使用缺省构造函数。
         3、基类定义了带有形参表构造函数,派生类就一定定义构造函数。

 否则:出现如下错误        

#include <iostream>

using namespace std;
class Base
{
public:
	Base(int a )
		:_b(a)
	{}
	~Base()
	{
		cout << "Base()" << endl;
	}
	int _B;
private:
	int _b;
};
class B
{
private:
	int _B1;
};
class Derive :public Base
{
public:
	Derive(int a)
		:Base(a)
		,_d(a)
	{}
	~Derive()
	{
		cout << "Derive()" << endl;
	}
private:
	int _d;

};
class D :public Base
{
public:
	D(int a)
		: _D(a)
	{}
	~D()
	{
		cout << "D()" << endl;
	}
	
private:
	int _D;
};
class DD :public B
{
public:
	
	~DD()
	{
		cout << "DD()" << endl;
	}
private:
	int _DD;
};
int main()
{
	Derive a(1);
	D b1;
	D b(1);
	DD c;
	/*Base b(1);*/
	/*a._B = 10;
	b._B = 1;
	c._B = 1;*/
	a.~Derive();
	system("pause");
	return 0;
}


三、继承体系中的作用域

1. 在继承体系中基类和派生类是两个不同作用域。(不能构成重载)
2. 子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以
使用 基类::基类成员 访问)--隐藏 --重定义
3. 注意在实际中在继承体系里面最好不要定义同名的成员。

#include <iostream>

using namespace std;
class Base
{
public:
	Base(int a = 1)
		:_b(a)
	{}
	void FunTest(int a)
	{ }
	~Base()
	{
		cout << "Base()" << endl;
	}
	int _B;
private:
	int _b;
};

class Derive :public Base
{
public:
	Derive(int a)
		:Base(a)
		,_d(a)
	{}
	void FunTest()
	{ }
	~Derive()
	{
		cout << "Derive()" << endl;
	}
	int _B;
private:
	int _d;

};

int main()
{
	Derive a(1);
	Base B;
	/*D b1;
	D b(1);
	DD c;*/
	/*Base b(1);*/
	/*a._B = 10;
	b._B = 1;
	c._B = 1;*/
	/*a.FunTest(a);*/// 不能形成重载
	a._B = 1; // 不能给基类赋值 a.Base::_B = 1; 对基类赋值
	a.~Derive();
	system("pause");
	return 0;
}



四、继承与转换--赋值兼容规则--public继承
1. 子类对象可以赋值给父类对象(切割/切片)
2. 父类对象不能赋值给子类对象
3. 父类的指针/引用可以指向子类对象
4. 子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)

    

友元关系不可继承


五、多继承

          

#include <iostream>
using namespace std;
class B1
{
public:

	int _B1;
};
class B2
{
public:
	int _B2;
};
class D :public B1,public B2  //继承B1和B2 
{
public:

	int _D;
};
int main()
{
	
	D d;
	cout <<  sizeof(d) << endl;
	d._B1 = 0;
	d._B2 = 1;
	d._D = 2;
	system("pause");
	return 0;
}
调试得到:


对象d 的大小为3*4 = 12个字节, 取d地址, 从内存中可以看出 d的对象模型为



六、菱形继承

       如图所示继承:

                      


#include <iostream>
using namespace std;
class B
{
public:

	int _B;
};
class C1:public B
{
public:
	int _c1;
};
class C2:public B
{
public:
	int _c2;
};
class D :public C1,public C2  //继承B1和B2 
{
public:

	int _D;
};
int main()
{
	
	D d;
	cout <<  sizeof(d) << endl;
	//d._B = 0;   产生二义性问题
	d.C1::_B = 0;
	d.C2::_B = 1;
	d._c1 = 2;
	d._c2 = 3;
	d._D = 4;
	system("pause");
	return 0;
}

调试结果如图


得到对象模型


七、虚继承 

          虚继承关键字 :virtual   

    虚继承 避免了二义性问题

     

#include <iostream>
using namespace std;
class B
{
public:

	int _B;
};
class C1:virtual public B
{
public:
	int _c1;
};
class C2:virtual public B
{
public:
	int _c2;
};
class D : public C1, public C2  //继承B1和B2 
{
public:

	int _D;
};
int main()
{
	
	D d;
	cout <<  sizeof(d) << endl;
	d._B = 0;  // 产生二义性问题
	
	d._c1 = 1;
	d._c2 = 2;
	d._D = 3;
	system("pause");
	return 0;
}

调试:

d的大小为24, 对象模型为:


取d的地址发现前四个字节不是某个类成员变量的值,它其实是个地址 ,在内存2中输入前四个字节的内容发现 它前四个字节为0x00 00 00 00转化为十进制就是0  接着为0x 14 00 00 00 转化为十进制就是20。

这个地址是偏移量表格的地址。

偏移量表格里面放的是 相对于自己的偏移量以及相对于基类的偏移量。

如内存2中存放的内容:

第一个字节放的为0 相对于C1偏移量为0。

第二个字节放的为20 相对于B偏移量为20  即 &d+20 得到存放基类的地址。


欢迎各位,批评指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值