一、为什么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大概有什么方法了可以使用,否则,需要查看相应的子类。