类的普通成员函数的地址是静态的,在编译阶段已指定。
如果基类中有虚函数,对象的内存模型中有一个虚函数表,表中存放了基类的函数名和地址。
如果派生类中重定义了基类的虚函数,创建派生类对象时,将用派生类的函数取代虚函数表中基类的函数。
C++中的多态分为两种:静态多态与动态多态。
静态多态:也成为编译时的多态;在编译时期就已经确定要执行了的函数地址了;主要有函数重载和函数模板。
动态多态:即动态绑定,在运行时才去确定对象类型和正确选择需要调用的函数,一般用于解决基类指针或引用派生类对象调用类中重写的方法(函数)时出现的问题。
下面是一个C++示例代码,演示了静态多态和动态多态的使用。
静态多态
静态多态包括函数重载和函数模板,编译时确定函数地址。
#include <iostream>
// 函数重载示例
void print(int i) {
std::cout << "Printing int: " << i << std::endl;
}
void print(double d) {
std::cout << "Printing double: " << d << std::endl;
}
void print(const std::string& s) {
std::cout << "Printing string: " << s << std::endl;
}
// 函数模板示例
template <typename T>
void show(T value) {
std::cout << "Showing value: " << value << std::endl;
}
int main() {
// 函数重载
print(10);
print(3.14);
print("Hello, C++");
// 函数模板
show(20);
show(4.56);
show("Template Function");
return 0;
}
动态多态
动态多态通过虚函数实现,运行时确定函数地址。
#include <iostream>
class Base {
public:
virtual void show() {
std::cout << "Base::show()" << std::endl;
}
};
class Derived : public Base {
public:
void show() override {
std::cout << "Derived::show()" << std::endl;
}
};
void demonstrate(Base* basePtr) {
basePtr->show(); // 调用虚函数,根据对象类型动态绑定
}
int main() {
Base baseObj;
Derived derivedObj;
Base* basePtr = &baseObj;
Base* derivedPtr = &derivedObj;
demonstrate(basePtr); // 输出 Base::show()
demonstrate(derivedPtr); // 输出 Derived::show()
return 0;
}
解释
-
静态多态:
- 函数重载:
print
函数有三个重载版本,分别接受int
、double
和string
类型参数。 - 函数模板:
show
函数模板可以接受任何类型参数。
- 函数重载:
-
动态多态:
- 基类
Base
中定义了虚函数show
。 - 派生类
Derived
重写了基类的虚函数show
。 demonstrate
函数接受Base*
类型参数,调用show
函数时根据传入对象的实际类型动态绑定到相应的函数实现。- 在
main
函数中,分别使用Base
和Derived
对象调用demonstrate
函数,展示了动态多态的效果。
- 基类
这个示例展示了静态多态和动态多态的基本用法,通过函数重载、函数模板和虚函数实现不同类型的多态。