什么时候使用虚函数?
当你需要一个函数在派生类中有不同表现的时候这时候你可以使用虚函数
比如一条水果流水线 作用都是传送物品削皮
流水线A 处理苹果
流水线B 处理菠萝
纯虚函数
必须被重写否则报错,一个类只要有一个纯虚函数那么他就是抽象类(abstract)无法实例化
一个类如果只要纯虚函数那么就是一个接口(interface) 接口也是抽象类
虚函数和纯虚函数
纯虚函数必须被重写否则报错,虚函数可以被重写也可以不被重写
#include<iostream>
#include<stdio.h>
using namespace std;
/*
当你需要一个函数在派生类中有不同表现的时候这时候你可以使用虚函数
虚函数代表的是子类可以重写父类的虚函数
纯虚函数就是子类必须重写父类的纯虚函数,否则编译报错
虚函数virtual等价于C#中的虚函数
纯虚函数 virtual {} =0 等价于C#中的abstract函数即抽象函数,只要有一个纯虚函数就是抽象类 抽象类不能实例化,只能有子类去实例化
如果一个类只有纯虚函数那么他可以被称之为接口,也是抽象类。等价于C#中的Interface.
override 重写:函数名,参数列表,返回值是一样的函数里面的计算啊算法啊不一样
overload 重载:参数列表,返回值类型不一样 只有函数名是一样的 形参可以从2个int 变为3个1个float 一个char 一个int
*/
/*
当一个类中有被声明为virtual的函数,就会为其创建一个虚函数表VTABLE
虚函数表实际上是一个函数指针的数组,每个虚函数就会占用一个这个数组的位置 一个类不管有多少个实例都只有一个虚函数表
派生类创建的时候也会创建一个虚函数表,也是一个函数指针的数组,派生类的VTABLE和基类的VTABLE的排列顺序一样,并且同名的虚函数会放在相同的数组位置上
这样创建派生类实例的时候会生成一个vprt就指向当前类的的VTABLE,这样就可以找到用的哪些虚函数啦
*/
class base
{
public:
base() {}; //尽管有虚析构函数但是没有虚构造函数
//base() { bad(); };//请不要在构造函数里面调用虚函数这样无论怎样都是调用基类的这个虚函数 即便你在派生类中重写了
//~base() { cout << "delete base" << endl; };//如果这样写在delete uB,delete uA的时候 class A ,class B的析构函数并不会被调用 只会调用class base的析构函数
virtual~base() { cout << "delete base" << endl; };//所以我们需要使用虚析构函数
virtual void bad(){ cout <<"base" << endl; };
virtual void fool()=0; //纯虚函数 其子类必须实现纯虚函数否则编译器报错
//virtual void SetB(int n) = 0; 如果一个类使用了纯虚函数那么这个类就是抽象类 其子类必须实现纯虚函数
virtual void sub(int a, int b) { cout << a - b << endl; };//虚函数可实现也可以不实现
virtual void add(int a, int b) { cout << a + b << endl; };
virtual void setA(int n) const { cout << n << endl; };
virtual void setB(int n) { j = n; cout << j << endl; };
void print() { cout << "printf" << endl; };//当然如果一个函数在他的派生类的表现都是一样的那么只需要一个正常函数即可
private:
virtual int change(int a, int b) { cout << a + b << endl; return a + b; };
int i = 50;
public:
int j = 1;
int k = 2;
int l = 3;
};
//子类的虚函数前面可以加virtual 来表明他实现的是虚函数
//也可以不加virtual使用override override会检查你是否完整重写了虚函数(函数名,参数列表,返回值类型是否和抽象类的虚函数相同)
//如果没有完整重写,一般情况下编译器不会报错,加上override编译器会报错
class B:public base
{
public:
B() {};
~B() { cout << "delete B" << endl; };
void fool() override { cout << "use B virtual function" << i << endl; };
void sub(int a, int b) override { ; cout << a - b - 1 << endl; };
virtual void bad() { cout << "B" << endl; };
virtual int change(int a, int b)override { return a - b; cout << a - b << endl; };//即便虚函数在基类是私有成员 派生类依旧可以重写并且实现多态
int can = change(11, 22);
private:
int i = 32;
};
class A :public base
{
public:
A() {};
~A() { cout << "delete A" << endl; };
void fool() override { cout << "use A virtual function" << i << endl; };
//virtual void setA(int n) { cout << n << endl; };//你如果这样写编译器他不会报错
//virtual void setA(int n) override { cout << n << endl; };//加上override之后会报错
virtual void setA(int n) const override { n = n + k; cout << n <<endl;/*k = 0; 报错 const 修饰不能修改成员变量*/ };//正确的写法是这样
virtual void setB(int n) override { k = 0; cout << k - n << endl; };
private:
int i = 64;
};
int main()
{
base* uB = new B();
uB->fool(); //use B virtual function32
uB->sub(3,4);//-2
uB->add(3,4);//7
uB->print();
uB->bad();
delete uB;
B* bptr = new B();
bptr->can;
cout << "bptr->can:" << bptr->can << endl;
base* uA = new A();
uA->fool();
uA->setA(8);//10
uA->setB(8);//-8
uA->print();
delete uA;
system("pause");
return 0;
}