继承与派生

首先,我们来认识一下类与类之间的关系有哪几种:

1、has_A 组合 包含关系,类中包含另一个类的对象

2、use_A 使用关系,类中使用了另一个类的成员函数

3、is_A 继承关系,B是特殊的A,B从A继承过来,A中有的B中都有

继承的语法: class 类名 :访问控制权限 要继承的类的名字 

class C_XY:public XY {};		// C_XY是继承自XY的子类(派生类),XY是C_XY的父类(基类)

1、访问控制权限:public 、protect 、private 主要讲一下protect属性,是保护属性,类的内部可用,外部不可用,其派生类的内部可用,外部不可用

1)公有继承(public)下,父类→子类:公有→公有(内外可用),保护→保护(内可用),私有→私有(不可用)。

2)保护继承(protect)下,父类→子类:公有→保护(内可用),保护→保护(内可用),私有→私有(不可用)。

3)私有继承(private)下,父类→子类:公有→私有(内可用),保护→私有(内可用),私有→私有(不可用)。

判断子类的访问权限可以依次判断:类的内外→继承方式→基类属性


2、对象模型:子类的排列方式是基类成员在前,本身的成员在后


3、类型兼容性原则:在需要基类对象的任何地方,都可以使用公有派生类的对象来替代,在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员。

1)子类对象可以当作父类对象使用

2)子类对象可以直接赋值给父类对象

3)子类对象可以直接初始化父类对象

4)父类指针可以直接指向子类对象

5)父类引用可以直接引用子类对象


4、继承中的构造和析构:

1)  派生类在进行构造时要调用父类的构造函数对父类变量进行初始化;

派生类新增的变量要调用自己的构造函数进行初始化;

对父类的成员参数初始化,在初始化列表中调用父类的构造函数。

2) 继承和组合混搭时的顺序:先父类,再子类对象,最后之类的构造函数。


5、派生类中有和基类同名的成员变量会屏蔽基类的成员,当然真正需要使用时,可以使用域解析符::来进行区分,如

b.A::a = 10;


6、重载和重定义:

1)  类中的函数重载必须发生在同一个类中;

派生类不能重载基类的函数,重载会屏蔽基类的所有同名函数,但同样,还是可以使用域解析符的。

2)  派生类的函数和基类的函数 函数原型一样,叫函数的重定义。重定义是发生在基类和派生类之间的。


7)static 关键字的继承

基类的静态变量是所有派生类共享的,因为它存在数据域中。 静态变量也遵循继承的访问控制。


8)多继承:一个类有多个基类的继承关系

class C : public A, public B{};
1) 派生类的基类的构造顺序和在继承列表中的声明顺序有关。

2)  多继承中的指针偏移:

A *pa = &c;
B *pb = &c;
C *pc = &c;
此时,pa 和 pc 指向 继承类中父类A成员的起始地址,但pb则指向的是继承类中父类B成员的起始地址,与pa和pc相差一个A的距离

3)但是,当一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类声明的名字进行访问时会产生二义性问题。

公共基类的调用不明确(::可以解决);

虽说调用不明确问题可以解决,但在构造派生类的时候公共基类的构造函数却还是会被调用2次,产生问题。

4)为了解决二义性问题,C++便引入了虚继承的概念,使公共基类在派生类中只产生一个子对象。

关键字: virtual

class B1: virtual public A{};
运用virtual 关键字之后,构造函数就只会被调用一次。但是当我们用sizeof 来测试类的大小时,发现类不仅没有变小,反而变大了。

经过一系列的测试,发现,在基类的父类成员中多了一个vbpter这样的虚基类指针:


该指针包含2个内容:当前类指针距离虚基类指针的偏移量 、 基类指针和虚基类指针的偏移量。

class A
{
public:
	int a;
};

class B1 : virtual public A
{
public:
	int b1;
};

class B2 : virtual public A
{
public:
	int b2;
};

class C :public B1,public B2
{
public:
	int c;
};
int main()
{
	C c;
	c.a  = 10;
	c.b1 = 20;
	c.b2 = 30;
	c.c  = 40;

	A  *pa  = &c;
	B1 *pb1 = &c;
	B2 *pb2 = &c;
	C  *pc  = &c;

	printf("pa = %p, pb1 = %p, pb2 = %p, pc = %p\n",pa,pb1,pb2,pc);

	return 0;
}
运行结果为: pa = 00CFF90C, pb1 = 00CFF8F8, pb2 = 00CFF900, pc = 00CFF8F8


这样的一个测试程序,从运行结果我们可以看出,pc和pb1 确实是指向B1首地址,而pb2与其相差8个字节,pa与其相差20个字节,所以vbptr确实是20和12。



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值