c++ 模板和对象多态的结合情况举例

本文通过C++中的模板和对象多态的实例,展示了如何在代码中实现类型无关且具有多态性的功能。通过Animal和其派生类(Dog和Cat),以及AnimalShelter模板类,展示了如何使用基类指针调用派生类的方法,实现灵活的动物叫声管理。

1.概要

模板和对象多态的结合情况举例

模板和多态的碰撞会擦出什么样的火花呢?
模板是忽略类型,啥意思,就是一个函数,来一个模板的对象,无论啥对象,我都按照一个套路处理。
多态呢,多态是根据对象不同有不同的行为,就是调用一个函数,会因对象不同有不同的行为。

他们俩的具体差别其实,可以这样理解,泛型是作为函数的参数来处理的,而多态呢多态是因对象不同选择不同的函数的。多态是根据一个对象的处理,无论啥对象我都按照一个套路来,多态呢,同一个函数因对象的不同会有不同的行为。
泛型像这样 函数(泛型)
多态像这样 对象->函数()
其实把多态弄得在本质点是这样 对象->函数()=>函数(多态对象)
其实我们看到的是对象调用函数,本质上是函数引入了一个默认的zhis指针,所有的面向对象函数都有这样的一个指针;
函数的本质并没有变,如果你看到内存内部的函数多态的函数是完全名称不同函数,且每个函数都必有一个指向对象的参数。
所以模板和多态的结合就是,模板的处理套路是相同的,但只这个相同处理中因模板本身对象的多态会调用不同的函数有多态的行为,所以模板和多态的结合就是一个既把共性集中,又把个性独立的一种结合,高度依赖共性,又保持个性。可以把高内聚(模板),低耦合(多态)做到一个极致。

模板呢,是按照一个套路处理无论啥对象,那么按照一定的套路处理,就要求这个对象一定也有些共性。比如相加那就要求所有都行都能支持这个运算符,比如对吧,就比如好多和排序相关的容器,就必须要求对象支持对比。所以模板虽然是对所有的对象都执行一样的处理,但是对对象也是又要求的,首先对象得支持这些处理。这些处理又聚友多态的特点,那就是多态为这个泛型的处理提供的个性。

在C++中,模板和对象多态性的结合使用可以带来很大的灵活性。模板允许我们编写与类型无关的代码,而多态性则允许我们使用基类的指针或引用来操作派生类的对象。当我们将这两者结合时,可以编写出既类型无关又具有多态性的代码。

2.代码

#include <iostream>  
#include <vector>  
#include <memory>  
  
// 定义一个基类 Animal  
class Animal {  
public:  
    virtual ~Animal() {}  
    virtual void speak() const = 0;  
};  
  
// 定义派生类 Dog 和 Cat,继承自 Animal  
class Dog : public Animal {  
public:  
    void speak() const override {  
        std::cout << "Woof!" << std::endl;  
    }  
};  
  
class Cat : public Animal {  
public:  
    void speak() const override {  
        std::cout << "Meow!" << std::endl;  
    }  
};  
  
// 定义一个模板类,用于存储和管理 Animal 对象的指针  
template <typename T>  
class AnimalShelter {  
private:  
    std::vector<std::unique_ptr<Animal>> animals;  
public:  
    void adopt(std::unique_ptr<T> animal) {  
        animals.push_back(std::move(animal));  
    }  
  
    void letThemSpeak() const {  
        for (const auto& animal : animals) {  
            animal->speak(); // 多态性:使用基类的指针调用派生类的 speak 方法  
        }  
    }  
};  
  
int main() {  
    // 创建 AnimalShelter 对象,存储 Dog 和 Cat 对象  
    AnimalShelter<Animal> shelter;  
    shelter.adopt(std::make_unique<Dog>());  
    shelter.adopt(std::make_unique<Cat>());  
      
    // 让动物们“说话”  
    shelter.letThemSpeak(); // 输出: Woof! Meow!  
      
    return 0;  
}

3.运行结果

Woof!
Meow!

4.备注

在这个例子中:

我们首先定义了一个基类 Animal,它有一个纯虚函数 speak()。
然后定义了两个派生类 Dog 和 Cat,它们分别实现了 speak() 函数,以模拟狗和猫的叫声。
接着,我们定义了一个模板类 AnimalShelter,它用于存储和管理 Animal 对象的指针(实际上是 std::unique_ptr<Animal> 的智能指针)。这个类有一个 adopt 方法用于添加动物,以及一个 letThemSpeak 方法用于让所有的动物“说话”。
在 letThemSpeak 方法中,我们遍历存储的动物指针,并通过基类指针调用 speak() 方法。由于 speak() 是虚函数,因此实际调用的是相应派生类实现的版本,这体现了多态性。
在 main 函数中,我们创建了一个 AnimalShelter 对象,并向其中添加了一个 Dog 对象和一个 Cat 对象。然后调用 letThemSpeak 方法,结果会输出 Woof! 和 Meow!,分别表示狗和猫的叫声。
这个例子展示了模板如何与多态性结合使用。AnimalShelter 是一个模板类,它可以接受任何从 Animal 派生出来的类型,并利用多态性来统一处理这些类型。这种结合使得代码既类型无关又具有灵活性,可以轻松地扩展以支持更多的动物类型。

<think>嗯,用户想要了解多态性的示例,特别是在编程中的例子。首先,我需要回忆多态性的基本概念。多态性在面向对象编程中是一个核心概念,指的是同一个方法或函数在不同情况下表现出不同的行为。根据提供的引用资料,Java中的多态性包括方法重载重写,而C++中也有类似的机制,比如通过虚函数实现运行时多态。 用户可能需要具体的代码示例来理解这个概念。先从简单的例子开始,比如方法重载。在Java中,同一个类中有多个同名方法,但参数不同。比如,一个计算面积的类,可以有接受不同参数类型的方法。这样用户能直观看到同一个方法名处理不同输入的情况。 然后是方法重写,也就是子类覆盖父类的方法。例如,动物类有个“叫声”方法,子类如猫、狗各自实现不同的叫声。这样在调用时,根据对象的实际类型执行相应的方法,体现了运行时多态。引用[^1]提到了Java中的重写与多态性,这里可以引用。 接下来,可能需要更复杂的例子,比如接口多态。在C#中,不同的类实现同一个接口,比如IDocument,可以有Save方法的不同实现。这样在使用接口类型调用Save时,实际执行的是具体类的方法,这也是多态的表现。 另外,用户可能对动态多态静态多态的区别不太清楚。静态多态比如函数重载或模板(在C++中),而动态多态则是通过继承虚函数实现的。引用[^2]提到C++中的多态示例,比如一个人的不同角色,可以结合代码说明。 需要注意的是,用户提供的引用中有JavaC++的例子,所以应该涵盖这两种语言,可能还要其他语言如Python或C#,以展示多态的普遍性。同时,确保示例代码正确,符合各语言的语法规范,比如Java中使用@Override注解,C++使用虚函数等。 用户的问题可能还涉及多态的应用场景好处,比如提高代码的可扩展性维护性。但用户主要请求的是示例,所以重点应放在代码演示上,每个例子后简要说明其如何体现多态性。 最后,生成相关问题时要围绕多态的不同方面,比如类型、实现方式、优缺点,以及在不同语言中的具体应用,帮助用户深入理解。</think>### 多态性编程示例解析 多态性是面向对象编程的核心特性之一,允许不同对象对同一消息(方法调用)做出不同响应。以下是多态性的典型示例: --- #### 1. **方法重写(Override)实现运行时多态** **Java示例**: ```java class Animal { void sound() { System.out.println("动物发出声音"); } } class Cat extends Animal { @Override void sound() { System.out.println("喵喵喵"); } } class Dog extends Animal { @Override void sound() { System.out.println("汪汪汪"); } } public class Main { public static void main(String[] args) { Animal a = new Cat(); // 父类引用指向子类对象 a.sound(); // 输出“喵喵喵” a = new Dog(); a.sound(); // 输出“汪汪汪” } } ``` **核心机制**:父类引用指向子类对象时,调用被重写的方法会根据实际对象类型执行[^1]。 --- #### 2. **接口多态(C#示例)** ```csharp interface IDocument { void Save(); } class PdfDocument : IDocument { public void Save() { Console.WriteLine("保存为PDF格式"); } } class WordDocument : IDocument { public void Save() { Console.WriteLine("保存为Word格式"); } } class Program { static void Main() { IDocument doc = new PdfDocument(); doc.Save(); // 输出“保存为PDF格式” doc = new WordDocument(); doc.Save(); // 输出“保存为Word格式” } } ``` **特点**:接口定义规范,不同实现类通过接口调用方法时表现出多态性。 --- #### 3. **函数重载(Overload)实现静态多态** **C++示例**: ```cpp #include <iostream> using namespace std; class Calculator { public: int add(int a, int b) { return a + b; } double add(double a, double b) { return a + b; } }; int main() { Calculator calc; cout << calc.add(3, 5) << endl; // 输出8 cout << calc.add(2.5, 3.7) << endl; // 输出6.2 return 0; } ``` **解析**:同一类中通过参数类型或数量不同实现方法重载,编译时确定调用哪个方法[^2]。 --- #### 4. **动态多态C++虚函数)** ```cpp #include <iostream> using namespace std; class Shape { public: virtual void draw() { cout << "绘制形状" << endl; } }; class Circle : public Shape { public: void draw() override { cout << "绘制圆形" << endl; } }; class Square : public Shape { public: void draw() override { cout << "绘制正方形" << endl; } }; int main() { Shape* shape = new Circle(); shape->draw(); // 输出“绘制圆形” shape = new Square(); shape->draw(); // 输出“绘制正方形” delete shape; return 0; } ``` **关键点**:虚函数(`virtual`)实现运行时动态绑定,`override`关键字确保重写正确性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值