虚函数与纯虚函数的区别:
•
函数被定义为虚函数,有实现方法;函数被定义为纯虚函数,只有定义,没有实现方法。
虚函数:
class A{
public:
virtual void foo(){
cout << "A:foo()" << endl;
}
};
class C{
public:
virtual void foo() = 0; //没有实现方法
};
•包含虚函数的类可以有自己的对象;包含纯虚函数的类不能有自己的对象。
包含虚函数:
#include<iostream>
using namespace std;
class A{
public:
virtual void foo(){
cout << "A:foo()" << endl;
}
};
int main(){
A *a = new A();
a->foo();
return 0;
}
正确运行,并输出:A:foo()。
包含纯虚函数:
#include<iostream>
using namespace std;
class C{
public:
virtual void foo() = 0;
};
int main(){
C *c = new C();
return 0;
}
报错,该类是抽象的不能实例化。
•定义虚函数是为了允许基类的指针可以访问子类的这个函数;定义纯虚函数是为了起到规范作用,使得继承这个
基类
的子类必须实现这个函数的方法。
虚函数:
#include<iostream>
using namespace std;
class A{
public:
virtual void foo(){
cout << "A:foo()" << endl;
}
};
class B : public A{
public:
void foo(){
cout << "B:foo()" << endl;
}
};
int main(){
A *a = new B();
a->foo();
return 0;
}
程序正确运行,并输出:B:foo()。
纯虚函数:
#include<iostream>
using namespace std;
class C{
public:
virtual void foo() = 0;
};
class D : public C{
public:
void foo(){
cout << "D:foo()" << endl;
}
};
int main(){
D *a = new D();
a->foo();
return 0;
}
程序正确运行,并输出:D:foo()。
纯虚函数:
定义:
纯虚函数是在基类中定义,没有实现方法,继承该类的子类必须定义自己的实现方法。virtual type name() = 0;
意义:
一:为了方便使用多态性,常常在基类中定义纯虚函数。
二:提高了编码效率。
三:很多情况下,基类本身生成对象是不合适的,比如动物基类派生出猫、狗等子类,但是基类本身实例化生成
对象
就
不合适。
为了解决上述问题就引入了纯虚函数,包含纯虚函数的类是抽象类,不能生成对象,只能作为基类派
生成其
他类
,
派
生类必须定义属于自己的纯虚函数实现方法,假如子类只是继承基类的纯虚函数没有是实现方法,那
么该子类也是
抽
象类
不能实例化。
总结:
1、纯虚函数声明如下:virtual type name()=0;纯虚函数没有实现方法,
用来规范派生
类的行为
,包含
纯虚
函数
的
类
是抽象类,不能实例
化,
因为实例化这样的抽象数据结构没有意义,但是可以声明指向实现该抽象类的子类的指
针或
引用
。
如下:
class C{
public:
virtual void foo() = 0;
};
class D : public C{
public:
void foo(){
cout << "D:foo()" << endl;
}
};
C *a = new D();
a->foo();
2、
纯虚函数,如果子类没有实现方法,那么子类还是抽象类;实现纯虚函数的子类,该纯虚函数在子类中就变
成了虚
函数,孙子类可以覆盖该虚函数。由多态方式调用的
时
候动态绑定。
3、对于虚函数,父类和子类都有各自的版本,由多态方式调用的时候动态绑定。
4、
虚函数的定义如下:virtual type name() {content};虚函数必须有代码的实现,如果不实现将出现函数未定义
的错
误。
5、虚函数是c++实现多态的机制,核心理念是通过基类访问派生类的函数方法。
6、在动态分配堆上内存的时候,析构函数必须是虚函数,但没必要是纯虚函数。
7、友元函数不是成员函数,只有成员函数才可以是虚拟的,因此友元函数不能是虚函数。但可以通过让友元函
数调
用
虚拟成员函数来解决虚拟问题。
8、析构函数应当是虚函数,当delete时将调用相应对象类型的析构函数,如果指针指向的是子类对象,先调用子
类的
析构函数,再调用基类的析构函数。