C++ 类的继承

一、为什么C++需要用到“继承”

C++的继承,说到底就是使用父类(基类)来完成某一样事情嘛…

换一种说法,继承就是为了复用父类的方法。

二、研究的问题

1、子类以public来继承父类会怎么样?

继承之后,父类的public成员相当于变成子类的public成员,能在外部直接使用;而父类的protected成员变成子类的protected成员;父类的private成员却不能通过子类来访问。

2、子类以protected来继承父类会怎么样?

继承之后,父类的public和protected成员变成子类的protected的成员;父类的private成员依旧不能通过子类来访问。

3、子类以private来继承父类会怎么样?

这个时候,父类的public、protected成员变成子类的private成员;这个时候,父类的private成员依旧不能通过子类来访问。

4、父类的private权限的属性,为什么如此特别?

因为父类的有些东西不能与子类共有,或者不能被继承。比如,父亲的年龄被定义在private,儿子继承父亲的年龄能干嘛?这个属性是父亲特有的私有的。

5、子类和父类都有相同名字的方法,且传参也一样,那么子类对象会调用哪个?

调用子类的。

6、子类和父类的构造和析构顺序是什么?

构造时候,先子类后父类;析构时候,先父类后子类。遵循栈规则,即先进先后,后进先出。

7、子类构造时候怎么给父类的构造函数传参?

需要在子类的构造函数中显式调用,比如dog():animal("zhou")

8、子类的构造函数在外部定义,并且需要给父类构造函数传参,语法是怎么样的?

//外部定义的构造函数
dog::dog(int myage):animal("zhou"), age(myage)
{ 
	cout << "dog constructor" << endl;
}
//类中的声明
class dog:public animal
{
public:
	dog();
	...
private:
	int age;
protected:
	
};

外部定义时候,可以给父类构造函数传参,同时也可以初始化子类的属性。编译器可以区别出不同的符号,因为animal这个符号是class定义时候继承而来。

在类的声明中,构造函数不需要带初始列表,不然会报错。

9、在子类中,怎么主动调用父类中与子类同名的函数?

void dog::test()
{
	//hello();    		//1
	//this->hello();	//2
	//dog::hello();		//3
	
	animal::hello();		//显示地调用父类中的hello()函数
}

子类继承父类,本质是子类实例化的时候,在开辟一片空间保存父类,所以,父类的同名函数也保存下来。

在子类中,直接调用的函数优先调用自身类中的成员函数,因为调用1,实际是调用2。而3 是从作用域的角度来调用函数。利用这个特点,我们可以调用父类的同名函数。

这是C++的隐藏规则在作怪。直接调用 1 ,其实隐藏了很多细节;而使用作用域的方式调用,可以绕过这些隐藏规则。

10、父类指针对象可以指向子类吗?

可以,这相当于子类对象可以无条件地隐式类型转换为父类对象。不过父类指针对象只能调用子类中继承父类的那一部分方法,子类自身的方法不能被调用,这规则也适用于子类和父类同名的函数。

11、什么是不良继承?

比如圆和椭圆的问题,是圆继承椭圆,还是椭圆继承圆?不论谁继承谁,都很不妥,比如,圆有半径,而椭圆有长轴和短轴,这些属性在另一个类中都用不上。虽然类的有些方法有些方法被复用,但是是硬是要继承,还是造成不良的继承。归根到底,这两者不具备传递性。

12、什么是组合?

就是一个class内使用其它多个class的对象作为成员。类似于一个结构体,包含了其它的结构体。

比如,定义一个人,人有两只脚,我们可以这样定义:

class leg
{
	...
};

class person
{
	leg left_leg;
	leg right_leg;
	...
};

在OO设计原则中,优先选择组合的方式,然后才是继承。但也有缺点,它会令系统的对象增多。

13、怎么解决继承的二义性问题?

第一种二义性:父类的有同名的函数

class A
{
public:
	void hello() { cout << "A hello()" << endl; };
};

class B
{
public:
	void hello(){ cout << "B hello()" << endl; };
};

class C:public A, public B
{
	
};
int main()
{
	C c1;
	
	c1.hello();
	return 0;
}

这种情况下,c1调用hello()会产生歧义,不知道调用A的,还是B的hello().

解决的方法:显式指定调用的对象。c1.A::hello();


第二种二义性:菱形继承问题,使用虚函数来解决

什么是菱形继承问题?就是孙子类C中继承了B1和B2,而B1和B2同时继承了相同的一个父类A,这样就导致孙子类有两份A。
解决方案是让B1和B2虚继承A,C再正常多继承B1和B2即可.

原理解释:https://blog.csdn.net/xiejingfa/article/details/48028491

14、虚函数的本质是什么?

虚函数是在程序运行时候才去链接运行,从而实现多态。

15、抽象类的作用?

类中带有纯虚函数,那么这个类就是抽象类。抽象类不能被实例化。

抽象类是为了让语法和语义保持一致。比如,父类animal 和 子类cat。我们知道,动物可以吃食物,可以叫,但是具体怎么吃,怎么叫,我们不知道,为了保持语法和语义的一致性,我们把吃和叫的方法现在父类中声明为纯虚函数。而子类cat就可以具体实现吃和叫的方法。

还有一个作用,就是让程序员查看父类,就知道animal大概有什么方法了可以使用,否则,需要查看相应的子类。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值