多态,虚函数,纯虚函数
虚函数:
1 #include <iostream> 2 using namespace std; 3 4 #include <string> 5 6 using namespace std; 7 8 class Animals 9 { 10 public: 11 virtual void eat(); 12 Animals(string); 13 protected: 14 string name; 15 16 }; 17 18 Animals::Animals(string thename) 19 { 20 name = thename; 21 } 22 23 void Animals::eat() 24 { 25 cout<<"Animals "<<name<<" is eating"<<endl; 26 } 27 28 class Dog:public Animals 29 { 30 public: 31 void eat(); 32 Dog(string); 33 }; 34 35 Dog::Dog(string thename):Animals(thename) 36 { 37 } 38 39 void Dog::eat() 40 { 41 cout<<"Dog "<<name<<" is eating bone"<<endl; 42 } 43 44 int main() 45 { 46 Animals *p = new Dog("xiaohuang"); 47 p->eat(); 48 delete p; 49 return 0; 50 }
执行结果:
若第11行去掉virtual
可见方法如果不用虚函数,执行结果用基类的方法,子类的方法无法覆盖父类的方法。注意:这里创建指针是用的基类的类型,new的空间是子类的类型
纯虚函数:
纯虚函数的一般形式:virtual 返回类型 函数名(形参表)=0;
这里的"=0"并不是函数的返回值等于零,它只是起到形式上的作用,告诉编译系统"这是纯虚函数"。纯虚函数不具备函数功能,不能被调用。纯虚函数不必写实现,
如果一个类中至少有一个纯虚函数,那么就称该类为抽象类。所以上述中Animals类就是抽象类。对于抽象类有以下几个注意点:
1. 抽象类只能作为其他类的基类来使用,不能建立抽象类对象
2. 不允许从具体类中派生出抽象类(不包含纯虚函数的普通类)
3. 抽象类不能用作函数的参数类型、返回类型和显示转化类型
4. 如果派生类中没有定义纯虚函数的实现,而只是继承成了基类的纯虚函数。那么该派生类仍然为抽象类。一旦给出了对基类中虚函数的实现,那么派生类就不是抽象类了,而是可以建立对象的具体类
也就是说有实现就是具体类,没有实现就是派生类
虚函数和纯虚函数的比较:
1. 虚函数和纯虚函数可以定义在同一个类(class)中,含有纯虚函数的类被称为抽象类(abstract class),而只含有虚函数的类(class)不能被称为抽象类(abstract class)。
2. 虚函数可以被直接使用,也可以被子类(sub class)重载以后以多态的形式调用,而纯虚函数必须在子类(sub class)中实现该函数才可以使用,因为纯虚函数在基类(base class)只有声明而没有定义。
3. 虚函数和纯虚函数都可以在子类(sub class)中被重载,以多态的形式被调用。
4. 虚函数和纯虚函数通常存在于抽象基类(abstract base class -ABC)之中,被继承的子类重载,目的是提供一个统一的接口。
5. 虚函数的定义形式:virtual {method body}
纯虚函数的定义形式:virtual { } = 0;
在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时候要求前期bind,然而虚函数却是动态绑定(run-time bind),而且被两者修饰的函数生命周期(life recycle)也不一样。
6. 虚函数必须实现,如果不实现,编译器将报错,错误提示为:
error LNK****: unresolved external symbol "public: virtual void __thiscall
ClassName::virtualFunctionName(void)"
7. 对于虚函数来说,父类和子类都有各自的版本。由多态方式调用的时候动态绑定。
8. 实现了纯虚函数的子类,该纯虚函数在子类中就编程了虚函数,子类的子类即孙子类可以覆盖该虚函数,由多态方式调用的时候动态绑定。
9. 虚函数是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数
10. 如果一个类中含有纯虚函数,那么任何试图对该类进行实例化的语句都将导致错误的产生,因为抽象基类(ABC)是不能被直接调用的。必须被子类继承重载以后,根据要求调用其子类的方法。
11. c++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。因此,在子类从新声明该虚函数时,可以加,也可以不加,但习惯上每一层声明函数时都加virtual,使程序更加清晰。
下面是设置虚函数的注意事项:
1、只有类的成员函数才能声明为虚函数。
2、静态成员函数不能使虚函数,因为它不受限于某个对象。
3、内联函数不能使虚函数。
4、构造函数不能是虚函数。
多态:
多态性指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作。C++支持两种多态性:编译时多态性,运行时多态性。
a.编译时多态性:通过重载函数实现
b 运行时多态性:通过虚函数实现。
编译时的多态性特点是运行速度快,运行时的多态性是高度灵活和抽象
相关:【转载】C++之多态性与虚函数:http://www.cnblogs.com/CaiNiaoZJ/archive/2011/08/11/2134673.html
注意:继承时,要养成的一个好习惯就是,基类析构函数中,加上virtual,为什么要加上呢?
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class FatherClass 7 { 8 public: 9 FatherClass(); 10 virtual ~FatherClass(); 11 }; 12 13 FatherClass::FatherClass() 14 { 15 cout << "this is FatherClass constructor"<<endl; 16 } 17 18 FatherClass::~FatherClass() 19 { 20 cout << "this is FatherClass finalizer"<<endl; 21 } 22 23 class ChildClass:public FatherClass 24 { 25 public: 26 ChildClass(); 27 ~ChildClass(); 28 }; 29 30 ChildClass::ChildClass() 31 { 32 cout << "this is ChlidClass constructor"<<endl; 33 } 34 35 ChildClass::~ChildClass() 36 { 37 cout << "this is ChildClass finalizer"<<endl; 38 } 39 40 int main() 41 { 42 FatherClass *p = new ChildClass; 43 cout << "finished"<<endl; 44 delete p; 45 return 0; 46 }
有virtual:
没有virtual:
可见基类中没有使用虚函数,子类的析构函数没有被调用,这样会因其内存泄漏,是十分危险的
另外子类中的函数可以加virtual也可以不加virtual,为了规范最好加上