c++类继承中的虚函数

方法在基类中被声明为virtual的后,它在派生类中将自动成为虚方法。此时我们在派生类中将此方法声明不声明为virtual都没关系了,但是最好是声明出来好标记哪些方法是虚的。

如果一个方法在基类中没有使用关键字virtual,程序将根据声明时指针类型(也就是等号左边)选择方法。如果使用了virtual,程序将根据指针指向的对象的类型来选择方法。使用引用声明时的效果是一样的,因为引用的底层就是用指针实现的。

例如,如果析构函数不是virtual的,对象被删除时,则将只调用对应于指针类型的析构函数。如果析构函数是virtual的,则将调用相应对象类型的析构函数。下面代码中,会调用Derived的析构函数,然后再自动调用基类的析构函数。使用虚析构函数可以确保正确的析构函数序列被调用。因此,要作为基类的类的析构函数都应声明为虚函数。

#include<iostream>
using namespace std;

class Base {
public:
	Base() { cout << "base contructor" << endl; };
	virtual ~Base() { cout << "base destructor" << endl; };
	virtual void func() { cout << "base function" << endl; }
};
class Derived :public Base {
public:
	Derived() { cout << "derived contructor" << endl; };
	virtual ~Derived() { cout << "derived destructor" << endl; };
	virtual void func() { cout << "derived function" << endl; }
};

int main() {
	
	Base* p=new Derived;  //输出base constructor,derived constructor
	p->func();    //输出derived function
	delete p;     //输出derived destructor,base destructor
	return  0;
#include<iostream>
using namespace std;

class Base {
public:
	Base() { cout << "base contructor" << endl; };
	~Base() { cout << "base destructor" << endl; };
	void func() { cout << "base function" << endl; }
};
class Derived :public Base {
public:
	Derived() { cout << "derived contructor" << endl; };
	~Derived() { cout << "derived destructor" << endl; };
	void func() { cout << "derived function" << endl; }
};

int main() {
	
	Base* p=new Derived;  //输出base constructor,derived constructor
	p->func();    //输出base function
	delete p;     //输出base destructor
	return  0;
}

构造函数是不能被声明为虚函数的,创建一个派生类时,将调用派生类的构造函数而不是基类的,然后,派生类的构造函数会先使用基类的构造函数再使用自己的。因此,派生类不继承基类的构造函数,所以将类构造函数声明为虚函数是没什么意义的。

 

按值赋值与按指针或引用赋值的不同:

按值赋值导致只将Derived对象d的Base部分传给bv。所以调用的func函数也是Base的。但是派生类引用或指针在赋值时,可以被转换为基类引用或指针(隐式向上强制转换)。

#include<iostream>
using namespace std;

class Base {
public:
	virtual void func() { cout << "base function" << endl; }
};

class Derived :public Base {
public:
	virtual void func() { cout << "derived function" << endl; }
};

int main() {
	Derived d;

	Base *bp=&d;
	bp->func();   //输出derived function	

	Base bv = d;
	bv.func();    //输出base function	
}

虚函数的工作原理:

虚函数使用的是动态联编(晚期联编)。编译器处理虚函数的方法是,给每个对象添加一个指向虚函数表的指针。虚函数表中存储了该类中所有虚函数的地址。(每个类的对象对应一个指针,每个类对应一个虚函数表)例如,基类对象包含一个指针,该指针指向基类的虚函数表。派生类对象会包含一个指向派生类虚函数表的指针,如果派生类重新定义了基类中某些的虚函数,该函数表将保存新的函数的地址。对于派生类没有重新定义的基类虚函数,该表将会保存原始版本函数的地址。

c++类继承中的虚函数