c++
虚函数
1.定义:在某基类
中
声明为 virtual 并在一个或多个派生类
中
被重新定 义的成员
函数
[1]2.语法:virtual
函数
返回类型
函数
名(
参数
表) {
函数
体 }3.用途:实现多态性,通过指向派生类的基类指针,访问派生类
中
同名覆盖成员
函数
,也就是允许子类override父类同名方法。
虚函数
的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员
函数
,在定义了
虚函数
后,可以在基类的派生类
中
对
虚函数
重新定义,在派生类
中
重新定义的
函数
应与
虚函数
具有相同的形参个数和形参类型(也就是完全相同的方法,不能只是
函数
名相同。)。以实现统一的接口,不同的定义过程。如果在派生类
中
没有对虚
派生一个类的原因并非总是为了继承或是添加新的成员,有时是为了重新定义基类的成员,使得基类成员“获得新生”。面向对象的程序设计真正的力量不仅仅是继承,而且还在于允许派生类对象像基类对象一样处理,其核心机制就是多态和动态联编。
(一)多态性
多态是指同样的消息被不同的对象接收时导致不同的行为。所谓消息是指对类成员
函数
的调用,不同的行为是指的不同的实现,也就是调用了不同的
函数
。
1)多态的分类
广义上说,多态性是指一段程序能够处理多种类型对象的能力。在
C++
中
,这种多态性可以通过重载多态(
函数
和运算符重载),强制重载(类型强制转换),类型
参数
化多态(模板)
,包含多态(继承与
虚函数
)四种方式
比如 一个
函数
chat(link &a); chat(ling *a); 前者引入一个地址
做
形参 是不是可以把一个指针变量p。。 这么用chat(p); 那跟第二个
函数
有什么区别呢 都是传地址啊。。 小弟弄不明白~~ chat(int&a); chat(int *a); 这两个
函数
是完全不同意义的东西,你的理解主要是在int&a和int* a这个类型上面。要注意int&和int*是两个完全不同的类型。int&是引用类型,而int*是指向int类型变量的指针类型。 void chat(int&a) { a=20; } 调用此
函数
: int x=100; chat(x); // 此时x的值变为
我们知道,在同一类
中
是不能定义两个名字相同、
参数
个数和类型都相同的
函数
的,否则就是“重复定义”。但是在类的继承层次结构
中
,在不同的层次
中
可以出现名字相同、
参数
个数和类型都相同而功能不同的
函数
。
人们提出这样的设想,能否用同一个调用形式,既能调用派生类又能调用基类的同名
函数
。在程序
中
不是通过不同的对象名去调用不同派生层次
中
的同名
函数
,而是通过指针调用它们。例如,用同一个语句“pt->display( );”可以调用不同派生层次
中
的display
函数
,只需在调用前给指针变量 pt 赋以不同的值(使之指向不同的类对象)即可。
打个比方,你要去某一地方办事,如果乘坐公交车,必须事先确定目的地,然后乘坐
只有用virtual声明类的成员
函数
,使之成为
虚函数
,不能将类外的普通
函数
声明为
虚函数
。因为
虚函数
的作用是允许在派生类
中
对基类的
虚函数
重新定义。所以
虚函数
只能用于类的继承层次结构
中
。
一个成员
函数
被声明为
虚函数
后,在同一类族
中
的类不能再定义一个非virtual的但与该
虚函数
具有相同的
参数
(包括个数和类型)和
函数
返回值类型的同名
函数
。
根据什么考虑是否把一个成员
函数
声明为
虚函数
?
① 看成员
函数
所在的类是否会作为基类
② 看成员
函数
在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该将它声明为
虚函数
。
如果成员
函数
在类被继承后功能不需修改,或派生类用不到
网上面试题
中
有一道以前没有想过,也没有试过的题。就是在继承关系
中
,
虚函数
中
如果有
默认
参数
,实际过程
中
,
默认
参数
是多少。
试验代码如下:
#include <iostream>
using namespace std;
class A {
public:
virtual void foo (int i = 1) {
cout << "foo in class A...
众所周知,
虚函数
是程序运行期间动态绑定的。这个是动态绑定的是基类指针对
虚函数
的绑定。但是,
虚函数
的
默认
参数
是怎样的呢?这是一个容易忽视的
问题
。答案是:
虚函数
的
默认
参数
是
静态
绑定的,也就是说在编译阶段就一定确定
默认
参数
的值。举例如下:
class Base
public:
Base() {}
~Base() {}
virtual void f (int
《Effective
C++
改善程序与设计的55个具体
做
法》条款37写道:绝不重新定义继承而来的缺省
参数
值。
静态
绑定:绑定的是对象的
静态
类型,某特性(比如
函数
)依赖于对象的
静态
类型,发生在编译期。
动态绑定:绑定的是对象的动态类型,某特性(比如
函数
)依赖于对象的动态类型,发生在运行期。
虚函数
可以有
默认
实参,但是,即便派生类有自己的
默认
实参,在使用使用基类指针调用时还是会
使用基类的
默认
实参。反之,如果使用派生类指针调用,则会使用派生类的
默认
实参(当然这就不
设计多态了,因为调用指针/引用是派生类,而不是基类)。
class A{
public:
A()=default;
virtual ~A()=default;
public:
virtual void func(int i = 10){
printf("A = %d\n",i);
class B :p
是的,我知道
c++
中
的
虚函数
的特点。
虚函数
是
c++
中
的一种特殊的
函数
,它具有动态绑定的特性。这意味着,当调用
虚函数
时,会在运行时根据对象的实际类型来确定应该调用哪个
函数
。这使得我们可以在继承体系
中
使用多态性,即使用基类的指针调用派生类的
函数
。
虚函数
通常用在基类
中
,并使用 virtual 关键字进行声明。派生类可以重写基类
中
的
虚函数
,以实现自己的版本。在调用
虚函数
时,会调用派生类
中
重写的版本,而不是基类
中
的版本。
class Shape {
public:
virtual void draw() = 0;
class Circle : public Shape {
public:
void draw() {
// 绘制圆形的代码
class Square : public Shape {
public:
void draw() {
// 绘制正方形的代码
int main() {
Shape *shape1 = new Circle;
Shape *shape2 = new Square;
shape1->draw(); // 调用 Circle::draw()
shape2->draw(); // 调用 Square::draw()
return 0;
在这个例子
中
,Shape 类是一个基类,Circle 和 Square 是派生类。Shape 类
中
的 draw() 是一个
虚函数
,它在 Circle 和 Square 类
中
被重写。当调用 shape1->draw() 时,会调用 Circle 类
中
的 draw()
函数
,而调用 shape2->draw() 时,会调用 Square 类
中
的 draw()
函数
。