作者:Linux兵工厂
转自:电源网星球号
《必知必会之C++多态机制》
静态多态
#include <iostream>
// 函数重载示例
void print(int x) {
std::cout << "Integer: " << x << std::endl;
}
void print(double x) {
std::cout << "Double: " << x << std::endl;
}
int main() {
print(5); // 调用第一个 print 函数
print(3.14); // 调用第二个 print 函数
return 0;
}
2.模板: 模板是一种通用编程技术,允许编写与特定类型无关的代码。通过使用模板,可以在不同类型的参数上执行相同的操作,而无需为每种类型编写不同的函数。
#include <iostream>
// 模板示例
template <typename T>
void print(T x) {
std::cout << "Value: " << x << std::endl;
}
int main() {
print(5); // 实例化一个 int 类型的 print 函数
print(3.14); // 实例化一个 double 类型的 print 函数
print("Hello"); // 实例化一个 const char* 类型的 print 函数
return 0;
}
在静态多态中,函数调用的决定在编译时完成,因此性能更高。然而,静态多态的缺点是在编写代码时必须明确指定每个函数的具体版本,如果有大量的重载或模板,可能会导致代码量增加和可读性降低。
动态多态
动态多态(也称为运行时多态或晚期多态)是指在程序运行时根据对象的实际类型来决定调用哪个函数版本。动态多态性通过虚函数和继承来实现,在编译时无法确定函数调用的具体版本,而是在运行时根据对象的类型动态确定。
动态多态的实现需要满足以下两个条件:
1.基类中声明虚函数: 在基类中将函数声明为虚函数,这样编译器就会在运行时进行函数调用的动态绑定。
2.派生类重写虚函数: 派生类中可以通过重写(覆盖)基类中的虚函数来提供自己的实现。在调用这个虚函数时,会根据对象的实际类型来决定调用哪个版本的函数。
下面是一个简单的示例,演示了动态多态的用法:
#include <iostream>
// 基类
class Animal {
public:
// 虚函数
virtual void makeSound() {
std::cout << "Animal makes a sound" << std::endl;
}
};
// 派生类
class Dog : public Animal {
public:
// 重写基类的虚函数
void makeSound() override {
std::cout << "Dog barks" << std::endl;
}
};
// 派生类
class Cat : public Animal {
public:
// 重写基类的虚函数
void makeSound() override {
std::cout << "Cat meows" << std::endl;
}
};
int main() {
// 创建派生类对象
Dog dog;
Cat cat;
// 基类指针指向派生类对象
Animal* ptr1 = &dog;
Animal* ptr2 = &cat;
// 通过基类指针调用虚函数,实现多态
ptr1->makeSound(); // 调用的是派生类 Dog 的 makeSound() 函数
ptr2->makeSound(); // 调用的是派生类 Cat 的 makeSound() 函数
return 0;
}
Animal 类有一个虚函数makeSound(),而Dog和Cat类分别继承自Animal类并重写了makeSound()函数。在main()函数中,我们创建了Dog和Cat类的对象,并将基类指针指向这些对象,然后通过基类指针调用虚函数makeSound()。由于makeSound() 是虚函数,所以在运行时根据对象的实际类型来决定调用哪个版本的函数,从而实现了动态多态性。
父类指针指向子类对象
在 C++ 中,可以使用父类的指针来指向子类的对象,这是实现多态的一种常见方式。这种行为被称为向上转型(upcasting),它允许您通过基类的接口来操作派生类的对象。这在面向对象编程中是非常有用的,因为它使代码更加灵活和可扩展。
下面是一个简单的示例说明了如何使用父类的指针来指向子类的对象:
#include <iostream>
// 基类
class Base {
public:
virtual void display() {
std::cout << "Base class display() called" << std::endl;
}
};
// 派生类
class Derived : public Base {
public:
void display() override {
std::cout << "Derived class display() called" << std::endl;
}
};
int main() {
// 创建派生类对象
Derived derivedObj;
// 使用基类指针指向派生类对象
Base* basePtr = &derivedObj;
// 通过基类指针调用虚函数,实现多态
basePtr->display(); // 调用的是派生类的 display() 函数
return 0;
}
Base 是基类,Derived是派生类。Base类有一个虚函数display(),Derived类重写了display()函数。在main()函数中,我们创建了Derived类的对象derivedObj,然后使用Base类的指针basePtr指向了derivedObj。最后,通过basePtr调用display()函数,由于display()函数是虚函数,所以调用的是Derived 类中的版本,实现了多态行为。
方法调用
在 C++ 中,如果父类通过指针或引用调用一个虚函数,而这个虚函数在子类中被重写(override),那么调用的实际方法将取决于指针或引用所指向的对象的类型。这就是多态的体现。
具体来说,如果父类指针或引用指向的是子类对象,那么调用的方法将是子类中重写的版本;如果指针或引用指向的是父类对象,那么调用的方法将是父类中的版本。
下面是一个示例来说明这一点:
#include <iostream>
// 基类
class Base {
public:
virtual void show() {
std::cout << "Base class show()" << std::endl;
}
};
// 派生类
class Derived : public Base {
public:
void show() override {
std::cout << "Derived class show()" << std::endl;
}
};
int main() {
// 创建派生类对象
Derived derivedObj;
// 使用基类指针指向派生类对象
Base* basePtr = &derivedObj;
// 通过基类指针调用虚函数,实现多态
basePtr->show(); // 调用的是派生类的 show() 函数
return 0;
}
Base 类是基类,Derived 类是派生类。在 main() 函数中,我们创建了 Derived 类的对象 derivedObj,然后使用 Base 类的指针 basePtr 指向了 derivedObj。最后,通过 basePtr->show() 调用 show() 函数,由于 show() 是虚函数,因此调用的是 Derived 类中的版本,而不是 Base 类中的版本……更多内容,请点击“阅读原文”查看。
· 应用案例:工厂生产线电气设备维护与故障诊断
· 该怎么设计,PCB才能过100A的电流?
· 迟滞比较器在防抖电路中的应用
· 创新与挑战并存!罗姆谈电机驱动与控制的新需求与新发展