C++中虚函数及相关概念详解
立即解锁
发布时间: 2025-08-19 01:36:33 阅读量: 1 订阅数: 6 


C++面向对象编程入门与实践
# C++ 中虚函数及相关概念详解
## 1. 迟绑定(Late Binding)
在编程中,编译器有时会面临不清楚要编译哪个函数的情况。比如在非虚函数(NOTVIRT)中,对于表达式 `ptr->show();`,编译器总是会编译对基类中 `show()` 函数的调用。但在虚函数(VIRT)的情况下,编译器并不知道 `ptr` 所指向的具体是哪个类的对象,它可能指向 `Derv1` 类或 `Derv2` 类的对象。那么编译器该调用哪个版本的 `draw()` 函数呢?实际上,编译器此时并不知道该怎么做,所以它会将这个决策推迟到程序运行时。在运行时,当知道 `ptr` 指向的具体类时,就会调用相应版本的 `draw` 函数,这被称为迟绑定或动态绑定。而在编译时以正常方式选择函数则被称为早绑定或静态绑定。迟绑定虽然会带来一些开销,但能提供更强的功能和灵活性。
## 2. 抽象类和纯虚函数
### 2.1 抽象类的概念
当我们不想实例化某个基类的对象时,就称这个基类为抽象类。抽象类的存在仅仅是作为派生类的父类,用于实例化派生类的对象,它也可以为类层次结构提供一个接口。
### 2.2 纯虚函数的定义
要明确告诉使用类库的人不要实例化基类的对象,一个好的方法是在基类中至少放置一个纯虚函数。纯虚函数是在声明时添加了 `=0` 表达式的虚函数,例如:
```cpp
// virtpure.cpp
// pure virtual function
#include <iostream>
using namespace std;
class Base //base class
{
public:
virtual void show() = 0; //pure virtual function
};
class Derv1 : public Base //derived class 1
{
public:
void show()
{ cout << "Derv1\n"; }
};
class Derv2 : public Base //derived class 2
{
public:
void show()
{ cout << "Derv2\n"; }
};
int main()
{
// Base bad; //can’t make object from abstract class
Base* arr[2]; //array of pointers to base class
Derv1 dv1; //object of derived class 1
Derv2 dv2; //object of derived class 2
arr[0] = &dv1; //put address of dv1 in array
arr[1] = &dv2; //put address of dv2 in array
arr[0]->show(); //execute show() in both objects
arr[1]->show();
return 0;
}
```
这里的 `=0` 与赋值无关,只是用来告诉编译器这个虚函数是纯虚函数。如果在 `main()` 函数中尝试创建 `Base` 类的对象,编译器会报错,提示你正在尝试实例化抽象类的对象,并指出使该类成为抽象类的纯虚函数的名称。需要注意的是,虽然这只是一个声明,但通常不需要为基类的纯虚函数编写定义(如果需要也可以编写)。
### 2.3 纯虚函数的使用规则
一旦在基类中放置了纯虚函数,就必须在所有想要实例化对象的派生类中重写该纯虚函数。如果某个类没有重写纯虚函数,那么它本身也会成为抽象类,不能实例化对象(不过其派生类可能可以)。为了保持一致性,也可以将基类中的所有虚函数都设为纯虚函数。
## 3. 虚函数与 `person` 类
### 3.1 类的设计
这里以 `person` 类为例,它扩展了之前的示例,包含两个派生类:`student` 和 `professor`。`person` 类是抽象类,包含纯虚函数 `getData()` 和 `isOutstanding()`。`student` 类包含一个 `float` 类型的变量 `gpa`,表示学生的平均绩点;`professor` 类包含一个 `int` 类型的变量 `numPubs`,表示教授发表的学术论文数量。
```cpp
// virtpers.cpp
// virtual functions with person class
#include <iostream>
using namespace std;
class person //person class
{
protected:
char name[40];
public:
void getName()
{ cout << " Enter name: "; cin >> name; }
void putName()
{ cout << "Name is: " << name << endl; }
virtual void getData() = 0; //pure virtual func
virtual bool isOutstanding() = 0; //pure virtual func
};
class student : public person //student class
{
private:
float gpa; //grade point average
public:
void getData() //get student data from user
{
person::getName();
cout << " Enter student’s GPA: "; cin >> gpa;
}
bool isOutstanding()
{ return (gpa > 3.5) ? true : false; }
};
class professor : public person //professor class
{
private:
int numPubs; //number of papers published
public:
void getData() //get professor data from user
{
person::getName();
cout << " Enter number of professor’s publications: ";
cin >> numPubs;
}
bool isOutstanding()
{ return (numPubs > 100) ? true : false; }
};
int main()
{
person* persPtr[100]; //array of pointers to persons
int n = 0; //number of persons on list
char choice;
do {
cout << "Enter student or professor (s/p): ";
cin >> choice;
if(choice=='s') //put new student
persPtr[n] = new student; // in array
else //put new professor
```
0
0
复制全文
相关推荐










