必知必会之C++多态机制

文摘   2024-11-19 10:02   天津  

作者:Linux兵工厂

转自:电源网星球号

《必知必会之C++多态机制》


多态
在 C++ 中,多态(Polymorphism)是一种面向对象编程的重要概念,它允许不同类的对象对同一消息做出不同的响应。具体来说,多态性允许基类的指针或引用在运行时指向派生类的对象,并且根据对象的实际类型来调用相应的成员函数。
多态性是通过虚函数来实现的。当一个基类的成员函数被声明为虚函数时,派生类可以通过覆盖(重写)这个函数来提供自己的实现。在运行时,调用这个虚函数的时候,实际上调用的是指向对象的实际类型的版本。
C++ 中的多态性有两种形式:静态多态(编译时多态)和动态多态(运行时多态)。
1.静态多态(编译时多态): 主要是通过函数重载和模板实现的,例如,同一个函数名可以有多个版本,根据参数的类型和数量来决定调用哪个版本的函数。这种多态性在编译时就已经确定了。
2.动态多态(运行时多态): 主要是通过虚函数和继承实现的,例如,基类指针指向派生类对象,并调用虚函数。在运行时,根据对象的实际类型来决定调用哪个版本的函数。这种多态性在运行时才会确定。

静态多态

静态多态(也称为编译时多态或早期多态)是指在编译时就确定函数调用的方式,主要通过函数重载和模板来实现。在静态多态中,编译器在编译时根据函数的签名(函数名称和参数列表)来确定调用哪个函数版本。
静态多态主要有两种形式:
1.函数重载:函数重载允许在同一作用域内声明多个函数,它们具有相同的名称但参数列表不同。在调用函数时,编译器根据传递的参数的数量、类型和顺序来选择匹配的函数。
#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的电流?

· 迟滞比较器在防抖电路中的应用

· 创新与挑战并存!罗姆谈电机驱动与控制的新需求与新发展

· 加强技术优势,加速产品开发!东芝以创新电驱方案赋能可持续发展
· PPEC:零成本技术交底,赋能电源开发新范式
· 骏龙科技Open Lab助力工程师 — 更快更直接地验证方案的性能及可行性

点击阅读原文,继续阅读

电源网
中国电源行业优质门户网站-电源网官方账号,2002年8月创建,是一个有着二十多年历史的技术、商务、资讯、信息平台,集结电源电子行业专家、知名教授与实战高手,聚焦技术技能积累,提供前沿技术与产品动态。官网:www.dianyuan.com
 最新文章