【C++】继承

继承

在C++中,可以利用【继承】来利用已有的一个数据类型来定义一个新的数据类型

继承的格式

class [子类类名]: [权限]  [父类]


继承的分类

继承分类三类:公有继承,私有继承和保护继承

(1)公有继承

公有继承中,【基类】中的【公有成员】【保护成员】【派生类】中的访问权限不变,【基类】中的【私有成员】也不能被【派生类】所访问

class Base//基类
{
public:
	int _pub;//公有成员 _pub
protected:
	int _pro;//保护成员 _pro
private:
	int _pri;//私有成员 _pri
};

class P: public Base //p类为派生类,继承于 基类 Base
{
public:
	void FunTest()
	{
		cout << _pub << _pro << _pri;//试着访问以下三个不同权限的成员
	}
};
报错:

结论:

公有继承中,【派生类】可以访问【基类】【公有成员】【保护成员】,不能访问【私有成员】

在具体调用时(类外),【派生类】只可以访问【基类成员】【公有成员】

(2)私有继承

私有继承,会将【基类】中的【公有成员】变成【私有】

class Base//基类
{
public:
	int _pub;//公有成员 _pub
protected:
	int _pro;//保护成员 _pro
private:
	int _pri;//私有成员 _pri
};

class P: private Base //p类为派生类,继承于 基类 Base
{
public:
	void FunTest()
	{
		cout << _pub << _pro ;//试着访问公有成员和保护成员、、发现私有继承后的公有成员在类里还可以使用
	}
};

int main()
{
	P p;//定义一个派生类对象 p
	p._pub = 1;//访问以下p由Base类私有继承的 _pub成员
	system("pause");
	return 0;
}
报错:


结论:

私有继承中,【派生类】可以访问【基类】【公有成员】【保护成员】,不能访问【私有成员】

在具体调用时(类外),【派生类】不可以访问【基类成员】【公有成员】,因为已被设置为私有

(3)保护继承

保护继承中,【派生类】的【公有成员】会被设置为【保护】的

class Base//基类
{
public:
	int _pub;//公有成员 _pub
protected:
	int _pro;//保护成员 _pro
private:
	int _pri;//私有成员 _pri
};

class P: protected Base //p类为派生类,继承于 基类 Base
{
public:
	void FunTest()
	{
		cout << _pub << _pro ;//试着访问公有成员和保护成员、、发现私有继承后的公有成员在类里还可以使用
	}
};

int main()
{
	P p;//定义一个派生类对象 p
	p._pub = 1;//访问一下p由Base类公有继承的 _pub成员
	p._pro = 2;//访问一下p由Base类保护继承的 _pro成员
	p._pri = 3;//访问一下p由Base类私有继承的 _pri成员
	system("pause");
	return 0;
}
报错:

继承中,构造函数和析构函数的调用顺序

用事实说话,那就直接进行测试吧

class Base
{
public:
	Base()
	{
		cout << "Base()" << endl;
	}
	~Base()
	{
		cout << "~Base()" << endl;
	}
};

class P : public Base
{
public:
	P()
	{
		cout << "p()" << endl;
	}
	~P()
	{
		cout << "~P()" << endl;
	}
};

int main()
{
	P p;
	return 0;
}
结果:

这里我的理解为,要生成【派生类】的对象p,那么先调用【派生类】的构造函数

又由于继承于【基类】(某些成员来自于基类),又得调用【基类】的构造函数。在【基类】生成后,才可以真正生成【派生类】的对象。

这也就是先输出Base()再输出p()的原因

析构函数也是如此

合成默认构造函数

语法规定,c++中,在没有定义【构造函数】时,编译器会自动合成【默认的构造函数】

那么,【编译器】真的遵循了吗?

在VS的几个版本中,答案是【否定】

但也会在特定的情况下合成【默认构造函数】

class Base
{
public:
	Base()
	{
		cout << "Base()" << endl;
	}
};

class P : public Base
{
public:

};

int main()
{
	P p;
	system("pause");
	return 0;
}
在这种情况下,编译器会合成P的默认构造函数

进入反汇编查看:

此时,我们发现了调用了P的构造函数,但是我们没有定义,所以这便是默认的

其他情况下,不会合成默认构造函数

注意:和子对象类似,在【基类】中如果没有缺省的构造函数,【派生类】中需要自行给出构造函数,并在命令行参数中调用【基类】构造函数

class Base
{
public:
	Base(int i)
	{
		cout << "Base()" << endl;
	}
};

class P : public Base
{
public:

};

int main()
{
	P p;
	system("pause");
	return 0;
}
报错:

无法合成可用的构造函数

同名隐藏

【派生类】的成员或变量名和【基类】冲突时,必须加限定符,否则无论如何也找不到【基类】的成员

class Base
{
public:
	Base()
	{
		cout << "Base()" << endl;
	}
	~Base()
	{
		cout << "~Base()" << endl;
	}
	int _a;
};

class P: public Base
{
public :
	P()
	{
		cout << "p()" << endl;
	}
	~P()
	{
		cout << "~P()" << endl;
	}
	int _a;
};
void FunTest()
{
	P p;
	p._a = 1;//调用了 派生类 的_a
	p.Base::_a = 2;//必须加作用域限定符才能找到基类中的 _a
}

赋值兼容规则

(1)派生类对象可以直接给基类赋值

(2)基类对象可以直接引用派生类对象

多继承和菱形继承

多继承,故名思议,就是一个【基类】有多个【派生类】

然而,可能出现【菱形继承】

class A
{
public:
	int _a;
};

class B1:public A
{
public:
	int _b1;
};

class B2 :public A
{
public:
	int _b2;
};

class C : public B1, public B2
{
public:
	int _c;
};

int main()
{
	/*测试这几个类的大小*/
	cout << sizeof(A) << endl;//4
	cout << sizeof(B1) << endl;//8
	cout << sizeof(B2) << endl;//8
	cout << sizeof(C) << endl;//20
	C c;
	c.B1::_a = 1;
	c._b1 = 2;
	c.B2::_a = 3;
	c._b2 = 4;
	c._c = 5;
	return 0;
}
如果我们没有做任何处理,那么,访问A的成员_a必须加限定符

以便确定是B1类中的,还是B2类中的(这就产生了二义性)

经过处理后:

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()
{
	cout << sizeof(A) << endl;//4
	cout << sizeof(B1) << endl;//12
	cout << sizeof(B2) << endl;//12
	cout << sizeof(C) << endl;//3*8 = 24

	//加了virtual后,为B1、B2增加了默认的构造函数
	//变化如下
	//之前的构造函数,会传入地址.而虚拟继承的多传了一个1
	//B1对象会存一个虚拟指针,指向一块空间,空间存的是偏移的地址(自己和基类)
	//自己元素的位置和基类互换了
	
	C c;
	c._a = 1;
	c._b1 = 2;
	c._b2 = 3;
	c._c = 4;

	return 0;
}
图示如下:

总结:

1.对于公有继承方式:
  ·【基类】成员对其【对象】的可见性与一般类及其【对象】的可见性相同,【公有成员】可见,其他成员不可见。这里【保护成员】与【私有成员】相同。
  ·【基类】成员对【派生类】的可见性对【派生类】来说,【基类】的【公有成员】和【保护成员】可见:
   【基类】的【公有成员】和【保护成员】作为【派生类】的成员时,它们都保持原有的状态;【基类】的【私有成员】不可见:
   【基类】的【私有成员】仍然是私有的,【派生类】不可访问【基类】中的【私有成员】。
  ·【基类】成员对【派生类】【对象】的可见性对【派生类】【对象】来说,【基类】的【公有成员】是可见的,其他成员是不可见。
   所以,在公有继承时,【派生类】的【对象】可以访问【基类】中的【公有成员】;【派生类】的成员函数可以访问【基类】中的【公有成员】和【保护成员】。
2.对于私有继承方式:
  ·【基类】成员对其【对象】的可见性与一般类及其【对象】的可见性相同,【公有成员】可见,其他成员不可见。
  ·【基类】成员对【派生类】的可见性对【派生类】来说,【基类】的【公有成员】和【保护成员】是可见的:【基类】的【公有成员】和【保护成员】都作为【派生类】的【私有成员】,并且不能被这个【派生类】的子类所访问;【基类】的【私有成员】是不可见的:【派生类】不可访问【基类】中的【私有成员】。
  ·【基类】成员对【派生类】【对象】的可见性对【派生类】【对象】来说,【基类】的所有成员都是不可见的。
   所以,在私有继承时,【基类】的成员只能由直接【派生类】访问,而无法再往下继承。
3.对于保护继承方式:
   这种继承方式与私有继承方式的情况相同。两者的区别仅在于对【派生类】的成员而言,
  ·【基类】成员对其【对象】的可见性与一般类及其【对象】的可见性相同,【公有成员】可见,其他成员不可见。
  ·【基类】成员对【派生类】的可见性对【派生类】来说,【基类】的【公有成员】和【保护成员】是可见的:【基类】的【公有成员】和【保护成员】都作为【派生类】的【保护成员】,并且不能被这个【派生类】的子类所访问;【基类】的【私有成员】是不可见的:【派生类】不可访问【基类】中的【私有成员】。
  ·【基类】成员对【派生类】【对象】的可见性对【派生类】【对象】来说,【基类】的所有成员都是不可见的。
   所以,在保护继承时,【基类】的成员也只能由直接【派生类】访问,而无法再往下继承。




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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值