虚函数是构成C++多态的重要一步,今天来说一下虚函数!
虚函数:
在基类(或父类)中,使用virtual关键字对函数进行声明为并在一个或多个派生类(子类)中被重新定义的成员函数,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。
它的用法是这样的:virtual + 函数返回类型 + 函数名 +(参数表) {函数体}
首先我们要知道为什么要有虚函数这个东西?
我来看下下面这两段代码的结果再来说结果:
class A
{
public:
void fun()
{
cout << "class A" << endl;
}
};
class B : public A
{
public:
void fun()
{
cout << "class B" << endl;
}
};
int main()
{
A* p = new B;
p->fun();
return 0;
}
上述代码很简单,A* p = new B;创建B对象,拿A类型指针指向它,最后运行时,输出的是
?
但是我明明创建的是B对象啊,为什么会运行class A中的fun函数呢?来看下面代码演示:
class A
{
public:
virtual void fun()
{
cout << "class A" << endl;
}
};
class B :public A
{
public:
virtual void fun()
{
cout << "class B" << endl;
}
};
int main()
{
A* p = new B;
p->fun();
return 0;
}
和上述代码的唯一区别就是在父类A中和派生类中的fun函数中加了virtual,声明为虚函数
,运行结果是:
?
这个运行结果就达到了我们的预期结果,但是为什么加上virtual声明之后运行结果就不同了呢?
?虚函数的原理:
class A
{
int num;
public:
A(int x = 10)
{
}
virtual void fun()
{
cout << "class A" << endl;
}
};
class B :public A
{
int sum;
public:
B(int x = 10)
{
}
virtual void fun()
{
cout << "class B" << endl;
}
};
int main()
{
B b(10);
A a(50);
A* p = &b;
return 0;
}
来看下面的代码分析:
?通过上面我们知道了虚函数的原理,下面我来看一下派生类中成员函数对父类的完全覆盖和部分覆盖的区别:
完全覆盖(基类中所有的虚函数都在子类中被重写)
class A
{
int num;
public:
A(int x = 10)
{
}
virtual void fun()
{
cout << "class A" << endl;
}
virtual void pun()
{
cout << "class A::pun" << endl;
}
};
class B :public A
{
int sum;
public:
B(int x = 10)
{
}
virtual void fun()
{
cout << "class B" << endl;
}
virtual void pun()
{
cout << "class B::pun" << endl;
}
};
int main()
{
B b(10);
A* p = &b;
p->fun();
p->pun();
return 0;
}
运行结果:都是调用B中的函数? 没问题,符合我们的预期!
?部分覆盖(基类部分函数在派生类中没有进行重写或者是派生类声明了一些基类中没有的虚函数):
class A
{
int num;
public:
A(int x = 10)
{
}
virtual void fun()
{
cout << "class A" << endl;
}
virtual void pun()
{
cout << "class A::pun" << endl;
}
};
class B :public A
{
int sum;
public:
B(int x = 10)
{
}
virtual void fun()
{
cout << "class B" << endl;
}
virtual void show() //将class B中的成员函数pun改成show函数
{
cout << "class B::pun" << endl;
}
};
int main()
{
B b(10);
A* p = &b;
p->fun();
p->pun();
return 0;
}
首先来看,p指向的函数有两个,fun和pun,但是没有我们刚刚改过的函数show,也就是说,如果在基类中没有的成员函数,但是在继承类中声明为虚函数,也不起作用,不能通过指针来指向。
?运行结果:
?因此想要派生类和基类在函数名相同但是实现不同功能的同时,必须函数名相同,如果在派生类中重写基类中没有的函数,声明为虚函数也没用,不可以通过上述代码中的指针或引用来调用。只可以通过实例化对象来实现对函数的调用(这块虽然show函数声明为虚函数,本质相当于普通成员函数)
总结:
1.父类子类虚函数之间的关系不是重载,而是重写(同名覆盖)。
2.父类指针指向派生类对象的地址,若在有派生类中有基类的重写成员函数,那么父类指针就可以通过虚表去调用派生类的同名覆盖的函数,如若派生类将 基类没有的函数 声明为virtual虚函数,那么就不可以通过基类的指针去之现象该函数,只可以 通过实例化派生类对象去调用这个普通成员函数。
|