上一章节:
六、重学C++—深入探索new delete-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/146489554?spm=1001.2014.3001.5502
本章节代码:
cpp/staticPolymorphic.cpp · CuiQingCheng/cppstudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/cppstudy/blob/master/cpp/staticPolymorphic.cpp
目录
上一章节:
本章节代码:
一、引言
二、静态多态:编译期的 “角色定制”
1、定义编译期确定行为的多态
2、实现方式:函数重载/运算符重载/模板编程
2.1、函数重载:同一作用域内,函数名相同但参数不同(类型、数量、顺序)。
2.2、运算符重载:让运算符适配自定义。
2.3、模板编程:
(1)、函数模板:代码的魔法复制机
使用场景
(2)、类模板:数据结构的百变魔方
使用场景
四、总结
下一章节:
一、引言
C++ 多态就如同一个演员能在不同的戏剧里扮演多种角色。在编程里,多态意味着一个接口能有多种实现方式。
按照多态实现的方式,可分为如下:
二、静态多态:编译期的 “角色定制”
1、定义编译期确定行为的多态
静态多态是编译器在编译阶段就确定调用哪个函数的多态形式,就像电影开拍前,演员的角色早已写进剧本。
2、实现方式:函数重载/运算符重载/模板编程
2.1、函数重载:同一作用域内,函数名相同但参数不同(类型、数量、顺序)。
例如计算不同类型数据的加法:
// 函数重载int add(int a, int b) {return a + b;}double add(double a, double b) { return a + b; }
调用时,编译器根据参数类型自动匹配对应函数,就像快递员按地址精准送货。
2.2、运算符重载:让运算符适配自定义。
例如下重载"+" 跟"<<"
/**** C++ 多态* 一、静态多态(编译期确定)* 1、函数重载* 2、运算符重载* 3、模板编程: 模板函数,模板类*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>// arithmetic unit
// 运算单元
class AritchmeticUnit{double m_dPartOne{0.0};double m_dPartTwo{0.0};
public:AritchmeticUnit(){}AritchmeticUnit(double real1, double real2):m_dPartOne(real1), m_dPartTwo(real2){}// 函数重载int add(int a, int b) {return a + b;}double add(double a, double b) { m_dPartOne = a;m_dPartTwo = b;return a + b; }// 运算符重载AritchmeticUnit operator+(const AritchmeticUnit& a1){AritchmeticUnit retA(m_dPartOne + a1.m_dPartOne, m_dPartTwo + a1.m_dPartTwo);return retA;}// 重载 << 运算符用于输出friend std::ostream& operator<<(std::ostream& out, const AritchmeticUnit& c) {out <<"value: " << c.m_dPartOne << ", " << c.m_dPartTwo;return out;} };int main()
{AritchmeticUnit aritUnit;int iRet = aritUnit.add(3, 5);double dRet = aritUnit.add(4.12, 3.85);printf("iRet = %d, dRet=%f\n", iRet, dRet);AritchmeticUnit aritUnit1(3.88, 6.66);AritchmeticUnit aritUnit2 = aritUnit1+aritUnit;std::cout <<"aritUnit2: " << aritUnit2 <<std::endl;return 0;
}
注意:C++中不能重载的运算符 .( 成员运算符 ),.*(成员指针运算符),::( 作用域运算符 ),?:(条件运算符), sizeof
2.3、模板编程:
(1)、函数模板:代码的魔法复制机
想象一下,你是一位忙碌的魔法师,需要为不同类型的物品施展 “减法魔法”。如果每次都要为不同类型的物品编写一个特定的减法咒语,那可真是太繁琐了。好在 C++ 为我们提供了函数模板这个神奇的魔法复制机,让我们可以轻松应对各种类型的减法。
通俗一句话解释,不同对象的,相同处理行为的抽象。
// 函数模板template<typename T, typename M>T subtr(T& a, M& b){T ret;// 打印数的实际类型const char* chT = typeid(T).name();const char* chM = typeid(M).name();std::cout << "T type: " << chT << std::endl;std::cout << "M type: " << chM << std::endl;if(!(std::strcmp("i",chT) && std::strcmp("d",chM))){return ret;}T mB = (T)b;if (mB > a){ret = mB - a;}else{ret = a - mB;}return ret;}
使用场景
函数模板的使用场景非常广泛,尤其适用于那些需要对不同类型数据执行相同操作的情况。比如,我们可以编写一个通用的排序函数模板,用于对不同类型的数组进行排序;或者编写一个通用的查找函数模板,用于在不同类型的容器中查找元素。函数模板让我们可以编写一次代码,就能够处理多种类型的数据,大大提高了代码的复用性和可维护性。
(2)、类模板:数据结构的百变魔方
实例展示
现在,让我们把目光转向类模板,它就像是一个百变魔方,可以根据我们的需求变成各种不同的数据结构。假设我们想要创建一个通用的栈类,用于存储不同类型的数据。使用类模板,我们可以轻松实现这个目标。
// 定义一个类模板
template <typename T>
class Stack {
public:// 入栈操作void push(T element) {m_elements.push_back(element);}// 出栈操作T pop() {if (m_elements.empty()) {throw std::out_of_range("Stack is empty");}T top = m_elements.back();m_elements.pop_back();return top;}// 判断栈是否为空bool isEmpty() const {return m_elements.empty();}
private:std::vector<T> m_elements;
};// 创建一个存储整数的栈Stack<int> intStack;intStack.push(1);intStack.push(2);std::cout << "Popped from intStack: " << intStack.pop() << std::endl;std::cout << "Popped from intStack: " << intStack.pop() << std::endl;// 创建一个存储字符串的栈Stack<std::string> stringStack;stringStack.push("Hello");stringStack.push("World");std::cout << "Popped from stringStack: " << stringStack.pop() << std::endl;std::cout << "Popped from stringStack: " << stringStack.pop() << std::endl;
使用场景
类模板适用于那些需要创建通用数据结构或算法的情况。比如,标准模板库(STL)中的 vector、list、map 等容器类,都是使用类模板实现的。类模板让我们可以编写通用的数据结构和算法,而不需要为每种数据类型都编写一个特定的实现。这不仅提高了代码的复用性,还使得代码更加简洁和易于维护。
四、总结
静态多态像编译期的 “定制剧本”,靠函数重载、运算符重载和模板编程实现高效适配;让程序在统一接口下绽放多样可能,这正是 C++ 强大表现力的精彩体现!
下一章节:
八、重学C++—动态多态(运行期)-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147004745?spm=1001.2014.3001.5502