继承、多态——面试特别常见的C++八股文

抽象类(接口)

接口描述了类的行为和功能,而无需完成类的特定实现
抽象类的目的是作为基类。
特点:
1、不能实例化对象
2、一定有纯虚函数。
3、如果派生类没有实现父类的纯虚函数,则派生类变为抽象类

class Pet
{
public:
virtual void func()=0;
//虚函数尾部加上" =0 " 一个虚函数便被声明成为了一个纯虚函数
// 等于0表示该函数仅声明而没有函数体
};

虚函数——没啥神秘的,就是普通函数,除了有诸多特性

特性

1、不能用static来修饰!!!
2、一般专门用来被重写,是多态实现的关键
多态:基类的指针或引用可以根据其实际指向的对象类型来调用相应的函数。
多态原理:如果一个类有虚函数,那么他一定有一个虚函数表——一个类共享一个虚函数表,被存储在全局数据区
3、每个包含虚函数的对象都有一个指向虚函数表的指针,存储在对象内存头部。

多态举例

class Father
{	
	public:
	Father(){cout<<"father ok"<<endl;};
	~Father(){cout<<"father delete"<<endl;}
	virtual void test() = 0;	
	virtual void speak()
	{
	cout<<"speaking FATHER"<<endl;
	}
};
class Child: public Father
{
	public:
		Child(){cout<<"child ok"<<endl;};
		~Child(){cout<<"child delete"<<endl;}
		void test() override
		{
			cout<<"test"<<endl;
		}
		void speak() override
		{
			cout<<"speaking Child"<<endl;
		}		
}
int main()
{
	Father * p = new Child();
	p->speak();//调用的是Child的speak,但是是父类指针。
	return 0;
}

0、构造子类对象时:调用顺序为 基类构造函数、子类的虚函数指针初始化、子类构造函数
1、这里用父类的指针实现了子类的函数调用,就是多态
2、在子类中override重写,虽然没有加上virtual关键字,但是也是虚函数。
3、析构对象时,先调用子类析构,再父类析构
4、只要派生类中定义的函数与基类的虚函数具有相同的函数名、参数列表和常量性,就重写了父类函数(析构函数除外,析构函数一般不重名,但是实际上也重写了)

虚函数的注意事项

1、构造函数不能是虚函数:因为父类的构造函数是虚函数,因为多态,实际上应该调用子类的构造函数。而子类的vptr还未初始化。
2、该类作为基类,析构函数应该是虚函数
3、该类非基类,析构函数不需要是虚函数

举例说明

class Father
{	
	public:
	Father(){cout<<"father ok"<<endl;d1 = new int(3);};
	virtual ~Father(){cout<<"father delete"<<endl; delete d1;}
	virtual void test() = 0;	
	virtual void speak()
	{
	cout<<"speaking FATHER"<<endl;
	}
	int* d1;
};
class Child: public Father
{
	public:
		Child(){cout<<"child ok"<<endl;d2 = new int(2);};
		~Child(){cout<<"child delete"<<endl;delete d2;}
		void test() override
		{
			cout<<"test"<<endl;
		}
		void speak() override
		{
			cout<<"speaking Child"<<endl;
		}		
		int* d2;
}
int main()
{
	Father * p = new Child();
	p->speak();//调用的是Child的speak,但是是父类指针。
	delete p;
	return 0;
}

如果 Father 类的析构函数不是虚函数,当执行 delete p; 时
只会调用 Father 类的析构函数。
导致 Child 类中为 d2 分配的内存无法被释放

你可能感兴趣的:(就业准备,C++/ROS,debug,面试,c++)