C++三大特性之多态

server/2024/9/25 9:30:18/

前言

        关于多态,是c++中最重要的东西,通过虚函数来实现多态这种特性

一、多态的概念

        多态是面向对象编程(OOP)中的一个重要概念,它允许对象在不同的上下文中以不同的方式表现。这意味着相同的接口(函数、方法)可以在不同的类中有不同的实现,从而实现不同的行为。

在 C++ 中,多态主要有两种形式:

1. 编译时多态(静态多态)

编译时多态通过函数重载和模板实现。其特点是在编译阶段决定函数的具体调用方式。主要的实现方式有:

函数重载:多个函数具有相同的名称,但参数类型或个数不同。编译器会根据调用时提供的参数选择合适的函数版本。

void print(int i) {std::cout << "Integer: " << i << std::endl;
}void print(double d) {std::cout << "Double: " << d << std::endl;
}

模板:使用模板可以编写通用的代码,编译器根据传入的类型生成具体的函数或类。

template <typename T>
void print(T value) {std::cout << value << std::endl;
}

2. 运行时多态(动态多态)

运行时多态通过虚函数和继承实现。其特点是程序运行时才确定调用哪个函数。这是通过基类指针或引用指向派生类对象,并使用虚函数实现的。

虚函数(virtual functions):如果基类的函数被声明为虚函数,那么派生类可以覆盖该函数。在运行时,C++ 会根据实际对象的类型调用对应的派生类函数,而不是基类中的函数。

#include <iostream>
using namespace std;// 基类定义
class Animal {
public:// 定义虚函数virtual void sound() {cout << "Animal makes a sound" << endl;}// 普通函数void sleep() {cout << "Animal sleeps" << endl;}
};// 派生类 Dog
class Dog : public Animal {
public:// 覆盖基类的虚函数void sound() override {cout << "Dog barks" << endl;}
};// 派生类 Cat
class Cat : public Animal {
public:// 覆盖基类的虚函数void sound() override {cout << "Cat meows" << endl;}
};int main() {Animal* animal1 = new Dog();  // 基类指针指向派生类对象Animal* animal2 = new Cat();  // 基类指针指向派生类对象animal1->sound();  // 输出: Dog barksanimal2->sound();  // 输出: Cat meowsanimal1->sleep();  // 输出: Animal sleepsanimal2->sleep();  // 输出: Animal sleepsdelete animal1;delete animal2;return 0;
}

 二、模板

        为什么要在这里说到模板呢,是因为我本人对模板这个操作实现不怎么熟悉,尤其涉及到引用,对于引用,我无法和指针进行区分,但是这种方法在c++中用到比较多,所以必须克服

        

一、模板的基本概念

1. 函数模板

函数模板允许你编写一个函数,它可以接受不同类型的参数,而不必为每种类型编写不同的函数版本。

        通常我们写一个函数是这样写的

void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}

但是我们用了模板之后 ,用一个占位符来表示任意类型

template <typename T>  // T 是占位符,表示任意类型
void swap(T &a, T &b) {T temp = a;a = b;b = temp;
}

 上面这个就是一个函数模板,T 是一个模板参数,可以是任何类型。当你调用 swap 函数时,编译器会自动推导出具体的类型:

int x = 10, y = 20;
swap(x, y);  // T 被推导为 intdouble a = 1.1, b = 2.2;
swap(a, b);  // T 被推导为 double

 

2. 类模板

类模板类似于函数模板,但它用于创建一组通用类。例如,一个简单的栈类可以定义为模板类,使其可以处理不同类型的数据

template <typename T>
class Stack {
private:T arr[100];  // 数组存储元素,类型为 Tint top;
public:Stack() : top(-1) {}void push(T val) {arr[++top] = val;}T pop() {return arr[top--];}
};

 你就可以用 intdouble 或其他类型创建一个栈对象:

Stack<int> intStack;
intStack.push(10);
intStack.push(20);Stack<double> doubleStack;
doubleStack.push(3.14);
doubleStack.push(2.71);

 

二、引用在模板中的使用

引用在 C++ 中是一种指向变量的别名,它允许你直接操作变量的原始值,而不是它的副本。当模板结合引用使用时,特别在函数模板中,它能让我们更加高效地处理大型对象,因为我们不必复制整个对象。这里就是我无法区分的地方,是因为我对引用的概念不怎么熟悉,

  • 指针是一个变量,存储了另一个变量的内存地址,你可以对指针进行操作(如解引用、改变地址),并且它可以是 nullptr
  • 引用是另一个变量的别名,必须在声明时绑定一个已有的变量,并且之后不能更改引用所指向的对象。引用更加直接和简洁。
1. 引用作为函数模板参数

当使用模板时,通常我们会传递对象的引用来避免复制。例如,当你传递一个大的对象(如一个 std::vector)给函数时,直接传引用可以提高性能,并且允许函数修改原始对象:

template <typename T>
void printVector(const std::vector<T> &vec) {  // 使用引用来避免拷贝for (const T &element : vec) {std::cout << element << " ";}std::cout << std::endl;
}

 在上面的例子中,const std::vector<T> &vec 是一个常量引用,表示该函数不会修改传入的 vec 对象。这样,我们避免了向函数传递时进行不必要的拷贝,同时确保不会意外修改原始数据。

#include <iostream>
#include <vector>// 定义模板函数
template <typename T>
void printVector(const std::vector<T>& vec) {for (const T& element : vec) {std::cout << element << " ";  // 打印每个元素}std::cout << std::endl;  // 打印完后换行
}int main() {// 实例1:打印 int 类型的 vectorstd::vector<int> intVec = {1, 2, 3, 4, 5};std::cout << "Integer vector: ";printVector(intVec);  // 调用模板函数打印 int 类型的 vector// 实例2:打印 double 类型的 vectorstd::vector<double> doubleVec = {1.1, 2.2, 3.3};std::cout << "Double vector: ";printVector(doubleVec);  // 调用模板函数打印 double 类型的 vector// 实例3:打印 string 类型的 vectorstd::vector<std::string> stringVec = {"hello", "world", "template"};std::cout << "String vector: ";printVector(stringVec);  // 调用模板函数打印 string 类型的 vectorreturn 0;
}

 


http://www.ppmy.cn/server/121756.html

相关文章

[大语言模型-工程实践] 手把手教你-基于Ollama搭建本地个人智能AI助理

[大语言模型-工程实践] 手把手教你-基于Ollama搭建本地个人智能AI助理 Note: 草稿优化中&#xff0c;持续更新&#xff0c;相关代码将统一提供出来~ 1. Ollama简介 Ollama 是一个用于在本地环境中运行和定制大型语言模型的工具。它提供了一个简单而高效的接口&#xff0c;用于…

SpringMVC详细使用总结教程

一、SpringMVC 1.1 介绍 Spring MVC 是 Spring 框架中的一个模块&#xff0c;用于构建基于 Java 的 Web 应用程序。它基于 MVC&#xff08;Model-View-Controller&#xff09;架构模式&#xff0c;提供了一种灵活而强大的方式来开发 Web 应用程序。Spring MVC 框架充分利用了…

loadrunner个人笔记

创建场景配置&#xff1a; 两个同时 去四&#xff1a;日志、时间、模拟、其他自动事务 加一&#xff1a;首选项 1、写脚本&#xff0c;沟通官方、文件打印扫描 MFI-sw.support.gsd.imsc.sda.globalopentext.com support.casemicrofocus.com 支持资源 | Micro Focus | OpenT…

MyBatis-config.xml核心配置

MyBatis-config.xml 包含了会深深影响MyBatis行为的设置和属性信息&#xff0c;配置文档的顶层结构如下 environments&#xff08;环境配置&#xff09; environments用于配置数据库的URL信息&#xff0c;MyBatis-config可以动态配置多个数据源&#xff0c;用于连生产、预发、…

Linux学习 重定向 管道 流

重定向 管道 流 在 Linux 中一个命令的去向可以有 3 个地方&#xff1a;终端、文件、作为另外一个命令的入参。 而命令一般都是通过键盘输入&#xff0c;然后输出到终端、文件等地方&#xff0c;它的标准用语是 stdin 、 stdout 以及 stderr 。 标准输入stdin&#xff0c;终端接…

Ansible 自动化运维工具的使用

1 说明 1.1 Ansible简介 ansible是一种流行的自动化运维工具,基于python2-paramiko模块开发,集合了众多运维工具(puppet、cfengine、chef、func、fabric)的优点,实现了批量系统配置、批量程序部署、批量运行命令功能。 ansible是基于模块工作的,本身没有批量部署的能力…

python-list-append-method

Python 列表追加()方法 原文:https://www.geeksforgeeks.org/python-list-append-method/ Python List 追加() 方法用于在列表的末尾追加和添加元素。 **语法:**列表.追加(项) 参数: **项:**列表末尾要添加的项 返回: 该方法不返回值 示例 1:向列表中添加项目 计算机编程语言 …

vulnhub-prime1

目录 靶场环境解题过程 靶场环境 项目ip靶机&#xff08;prime&#xff09;未知攻击机&#xff08;kali&#xff09;10.128.129.128 解题过程 打开靶机&#xff0c;我们只能看见一个登录界面&#xff0c;上面只有半截提示 我们首先要做的是主机发现&#xff0c;因为是网络适…