函数重载与函数覆盖的区别及使用方法
函数重载和函数覆盖是C++中两种常见的函数特性,它们的作用和使用方法都有一些差别。本文将对这两种特性进行详细的介绍和比较,希望可以帮助读者更好的理解并运用它们。
函数重载
函数重载是指在同一个作用域内,定义了多个同名的函数,但它们的参数数量、类型或顺序不同,编译器会根据不同的参数列表自动选择调用对应的函数。函数重载的目的是为了方便程序员编写和调用函数,使得函数名能够更加直观、简洁。例如:
void print(int num) {
cout << "这是一个整数:" << num << endl;
}
void print(double num) {
cout << "这是一个浮点数:" << num << endl;
}
int main() {
print(10);
print(3.14);
return 0;
}
在这个例子中,我们定义了两个同名的函数print,但是它们的参数类型不同,一个是int,一个是double。当我们调用print函数时,编译器会自动根据参数的类型选择相应的函数。这样可以方便我们将不同类型的数据输出到屏幕上。
函数重载的使用方法:
函数重载需要注意以下几点:
- 函数名必须相同,但是形参列表必须不同
- 形参列表可以由参数个数,参数类型和参数顺序组成
- 返回类型和修饰符不是函数重载的条件
- 函数调用时,编译器会自动匹配合适的函数
- 函数重载可以对C++中的运算符进行定义
函数覆盖
函数覆盖是指在派生类中定义了一个与基类中同名、同参数列表、同返回类型的成员函数,那么就会发生函数覆盖。当在派生类中使用该函数名时,会优先使用派生类的函数覆盖基类的函数。因此,通过函数覆盖,我们可以在派生类中重写基类中的成员函数,从而实现多态性。
例如:
class Shape {
public:
virtual void draw() {
cout << "This is a shape." << endl;
}
};
class Circle : public Shape {
public:
void draw() {
cout << "This is a circle." << endl;
}
};
class Rectangle : public Shape {
public:
void draw() {
cout << "This is a rectangle." << endl;
}
};
int main() {
Shape *ptr;
Circle circle;
Rectangle rect;
ptr = &circle;
ptr->draw(); // 调用派生类中的函数
ptr = ▭
ptr->draw(); // 调用派生类中的函数
return 0;
}
在这个例子中,我们定义了一个基类Shape,其中有一个虚函数draw,然后我们定义了两个派生类Circle和Rectangle,它们中都覆盖了基类的draw函数。在main函数中,我们把Shape类型的指针ptr分别指向Circle和Rectangle对象,并调用draw函数,此时会根据指针所指对象的类型来确定调用哪个draw函数。
函数覆盖的使用方法:
函数覆盖需要注意以下几点:
- 覆盖的函数必须与基类中被覆盖的函数有相同的名称、参数列表和返回值类型
- 把基类中的函数声明为虚函数,可以使当前函数变为虚函数,实现多态性
- 覆盖的函数不能比基类的函数拥有更严格的访问权限
- 可以使用virtual关键字显式地声明覆盖函数
- 派生类也可以重载虚函数,此时派生类中的函数会屏蔽基类中的同名函数
函数重载和函数覆盖的区别
从上面的介绍和例子中,我们可以看到函数重载和函数覆盖有以下几个区别:
- 函数重载是在同一个作用域内,定义了多个同名的函数,但它们的参数数量、类型或顺序不同;函数覆盖是在派生类中定义了一个与基类中同名、同参数列表、同返回类型的成员函数。
- 函数重载可以返回不同类型的值;函数覆盖必须返回与基类相同类型的值。
- 函数重载是为了方便程序员编写和调用函数,而函数覆盖是为了实现多态性。
- 函数重载采用的是编译时多态;函数覆盖采用的是运行时多态。
总结
函数重载和函数覆盖是C++中两个非常常见的特性,它们分别用于解决不同的问题,需要在实际开发中加以区分和使用。如果程序员想在同一个作用域内定义多个同名的函数,并且它们的参数列表不同,那么可以使用函数重载;如果想在派生类中重写基类的成员函数,并且能够实现多态性,那么就需要使用函数覆盖。通过学习函数重载和函数覆盖,我们可以更好地理解C++中函数的一些特别之处,进一步提高自己的编程水平。
