c++继承和多态

版权声明:本节目由WolfOnTheWay独家播出 https://blog.csdn.net/qq_42214953/article/details/89418228

1.继承的本质是什么?

answer:继承的本质其实就是代码复用,派生类复用基类的代码。

2.派生类从基类继承来的成员的访问限定?

3.private和protected的区别?

private:声明的方法和属性,只能被定义方法和属性的类访问。

protected:声明的方法和属性只能被类本身和其继承的子类来进行访问。

4.派生类怎么初始化从基类继承来的成员?

answer:必须调用基类的构造函数来对继承来的成员来进行初始化。

5.重载、隐藏和覆盖

1、重载的条件:

answer:函数名相同,作用域相同  参数列表不同的函数之间。

2、隐藏的条件:

answer:基类和派生类之中,函数名相同的函数

class A
{
public:
	void show()
	{
		cout << "A.show()" << endl;
	}
};
class B :public A
{
public:
	void show()
	{
		cout << "B.show()" << endl;
	}
};
int main()
{
	B b;
	b.show();
	b.A::show();
	return 0;
}

程序打印结果为:

B.show()
A.show()

原因是,在派生类中重新声明了一个show()函数,从基类继承来的show()函数会被隐藏掉。要想访问从基类继承的show()函数,必须加上基类的作用域,这样就可以进行访问了。

3.覆盖的条件

answer:基类和派生类之中,函数的返回值,函数名,参数列表都相同,而且基类的函数是虚函数。

6、基类和派生类的相互赋值

class Base
{
public:
	Base(int a) :ma(a) { cout << "Base()" << endl; }
	~Base() { cout << "~Base()" << endl; }
	virtual void show() { cout << "Base::show()" << endl; }
	virtual void show(int i) { cout << "Base::show(int)" << endl; }
protected:
	int ma;
};
class Derive : public Base
{
public:
	Derive(int data) :Base(data), mb(data) { cout << "Derive()" << endl; }
	~Derive() { cout << "~Derive()" << endl; }
	virtual void show() { cout << "Derive::show()" << endl; }
private:
	int mb;
};
int main()
{
	Derive d(20);
	
	Base *pb = &d;
	pb->show(); //静态绑定 Base::show   call  Base::show (0E912DAh)
	/*
	动态绑定    vfptr vftable什么时候生成,运行时加载到哪块内存
	mov eax, dword ptr[pb]
	mov ecx, dword ptr[eax]
	call ecx
	*/
	cout << sizeof(Base) << endl;  // 4  8
	cout << sizeof(Derive) << endl; // 8  12

	// 识别的都是静态(编译时期)类型,显示识别的是RTTI run-time type infomation
	cout << typeid(pb).name() << endl;  // (静态 去掉基类和派生类的vurtual)Base*  (动态)Base*
	cout << typeid(*pb).name() << endl; // (静态 去掉基类和派生类的vurtual)Base   (动态)Derive

	return 0;
}

7、请解释静态(编译)绑定和动态(运行)绑定

如果一个类包含有虚函数,在类型在编译时期会产生一个对应的虚函数表,存虚函数得地址。运行得时候放在.rodata段。实例化对象得时候会产生一个指针,用于指向虚函数表得地址。一个类中定义一个虚函数和定义十个虚函数,只影响虚函数表的大小,不影响对象的大小。继承来的虚函数,编译的时候也会产生虚函数表。
 继承的时候 ,如果派生类之中里面有和基类函数名相同 ,参数列表相同的函数 ,如果基类中的此函数为虚函数,编译器会自动把派生类中的这部分代码处理为虚函数,且将地址存入虚函数表中,将虚函数表的地址作为派生类的一个成员属性。

8、怎么理解多态?

静态的多态:编译时期 函数重载和模板。
动态的多态:继承 虚函数。

9、RTTI运行时的信息类型。

RTTI指针存储在虚函数表vftable当中,指向一段类型字符串。

10、抽象类和纯虚函数

1、基类一般不代表任何实体,定义一些派生类共有的属性,一般不进行实例化。

2、virtual void bark () = 0;称为纯虚函数,拥有纯虚函数的类称为抽象类  ,纯虚函数必须在派生类中进行定义,否则派生类将没有意义,不能进行实例化。

3、抽象类和普通类最大的区别是:抽象类不能进行实例化,但是可以定义指针和引用。

11、继承中的几点问题?

1.析构函数能不能实现成虚析构函数?

answer:可以。将析构函数声明为虚析构函数,当基类指针指向派生类对象的时候,这时候通过基类指针来释放派生类对象,虚析构函数就显得特别有用。

2.在构造/析构函数中调用虚函数,是静态绑定还是动态绑定?

answer:构造函数中是不会发生动态绑定的,因为虚函数是依赖对象的,在构造函数中国对象还没有进行实例化。

在析构函数中也不要调用虚函数。在析构的时候会首先调用子类的析构函数,析构掉对象中的子类部分,然后在调用基类的析构函数析构基类部分,如果在基类的析构函数里面调用虚函数,会导致其调用已经析构了的子类对象里面的函数,这是非常危险的。

3、静态成员函数是和类进行对应的,因此是不能进行动态绑定的。内联函数以前不能进行动态绑定,现在可以。

4、什么时候析构函数必须写成虚析构函数?

answer:当基类指针或引用指向堆上创建的派生类对象的时候。

5、用对象调用虚函数永远是静态绑定,动态绑定首先要用指针或者引用来调用虚函数。

12、多重继承

1、多重继承的坏处?

answer:在菱形继承中,最下面的派生类会有两份间接基类的成员属性。

2、怎么解决?

answer:虚基类(虚继承),会产生虚基类指针,相当于虚函数表的虚函数表的指针。

3、虚基类是什么?

answer:http://www.cnblogs.com/yiranlaobaitu/p/3764422.html

 

猜你喜欢

转载自blog.csdn.net/qq_42214953/article/details/89418228
今日推荐