C++ 多态

今天问到关于C++的多态性,作为面向对象的三大特性之一,这个也是很基础的,结果一时紧张,只答出来了使用虚函数来实现的多态这一点,后来面试官说还有模板呢啊,恍然大悟,回来后就多态性仔细又看了看,现在总结一下

 

所谓多态,字面意思就是 多种状态,使用方面统一的接口来实现不同的操作,大家熟知的使用虚函数来实现的多态叫运行时的多态,此外还有静态多态,就是在编译时候就已经确立了状态关系,此外,还流传着两个多态的说法,一说是 函数多态,一说是 宏多态,下面来一一介绍

 

一、函数多态

我们想,如果要用函数来统一接口,那要怎么办,自然而然想到的是函数重载,使用相同的函数名,但是函数参数列表不论是类型或者长度却不相同,用这种方法来实现多态,不过我想函数重载和模板就多态来讲其实是一样的,只不过是重载函数的话我们要写多个函数,而模板的话我们使用typedef,只要写一个函数,在调用的时候,会根据参数的类型自己去替换匹配而已。不过如果对于不同类型的操作,函数的实现方法不一样而已

  1. #include<iostream>  
  2. #include<string>  
  3. using namespace std;  
  4.   
  5. int add(int num1,int num2)  
  6. {  
  7.     return num1+num2;  
  8. }  
  9.   
  10. int add(int num1,string str1)  
  11. {  
  12.     return num1+atoi(str1.c_str());  
  13. }  
  14.   
  15. void main()  
  16. {  
  17.     /*函数多态*/  
  18.     int num1=10;  
  19.     int num2=20;  
  20.     int result=add(num1,num2);  
  21.     cout<<"函数多态 add(int num1,int num2)的结果是:"<<result<<endl;  
  22.     string str1="22";  
  23.     result=add(num1,str1);  
  24.     cout<<"函数多态 add(int num1,string str1)的结果是:"<<result<<endl;  
  25.       
  26. }  

这样的话编译器会根据不同的参数列表,对函数进行重新整合,两个重载函数的函数名字就会发生改变

 

二、宏多态

宏多态,就是在定义的宏中含有变量,这样在宏替换的时候,相应的变量也替换了,这样宏中可以带任意的参数类型

  1. #include<iostream>  
  2. #include<string>  
  3. using namespace std;  
  4.   
  5. #define ADD(A,B) A+B  
  6.   
  7. void main()  
  8. {  
  9.     /*宏多态*/  
  10.     int num1=10;  
  11.     int num2=20;  
  12.     string str1="22";  
  13.     string str2="33";  
  14.     cout<<"宏多态 ADD(A+B) A+B:"<<ADD(num1,num2)<<endl;  
  15.     cout<<"宏多态 ADD(A+B) A+B:"<<ADD(str1,str2)<<endl;  
  16. }  

 

三、动态多态

在C++中主要使用继承机制和虚函数来实现,通过基类的指针或者引用,指向子类对象,来调用虚函数,这样会导致相应对象的虚函数被调用,因为我们统一使用的基类指针或引用,所以在编译时候不能确定调用的是那个虚函数,或许虚函数最方便的地方时在处理一个集合中,各个对象不同的时候,如下代码

 

  1. #include<iostream>  
  2. #include<string>  
  3. #include<vector>  
  4. using namespace std;  
  5. /*虚函数机制*/  
  6. class Base  
  7. {  
  8. public:  
  9.     virtual void print()=0;  
  10. };  
  11.   
  12. class Child1:public Base  
  13. {  
  14.     void print()  
  15.     {  
  16.         cout<<"我是Child1类"<<endl;  
  17.     }  
  18. };  
  19. class Child2:public Base  
  20. {  
  21.     void print()  
  22.     {  
  23.         cout<<"我是Child2类"<<endl;  
  24.     }  
  25. };  
  26. /*如果容器中函数的对象是不同类的,那么这时候用使用多态是非常的方便的*/  
  27. void function(const vector<Base*>&V)  
  28. {  
  29.     for(int i=0;i<V.size();++i)  
  30.     {  
  31.         V.at(i)->print();  
  32.     }  
  33. }  
  34.   
  35. void main()  
  36. {  
  37.     /*虚函数多态*/  
  38.     Child1 child1;  
  39.     Child2 child2;  
  40.     Base *p;  
  41.     p=&child1;  
  42.     p->print();  
  43.     p=&child2;  
  44.     p->print();  
  45.     vector<Base*>BaseVector;  
  46.     BaseVector.push_back(&child1);  
  47.     BaseVector.push_back(&child2);  
  48.     function(BaseVector);  
  49. }  

 

四、静态多态

 

如果使用模板来实现上面那个例子,那么我们不需要让这两个类继承同一个父类,在编译的时候,会产生两个不同的函数,静态多态会导致程序变大,但是这样的话会比运行时的多态效率更高,但是我们使用函数模板的话就没办法处理异质对象了,就是在函数模板中如果操作容器的话,而容器里面的对象又不相同,因为我们没办法把两个不同类型的对象放到同一个容器中,所以更常用的方法是将动态多态和静态多态结合起来

 

  1. #include<iostream>  
  2. #include<string>  
  3. #include<vector>  
  4. using namespace std;  
  5. /*虚函数机制*/  
  6. class Base  
  7. {  
  8. public:  
  9.     virtual void print()=0;  
  10. };  
  11.   
  12. class Child1:public Base  
  13. {  
  14.     void print()  
  15.     {  
  16.         cout<<"我是Child1类"<<endl;  
  17.     }  
  18. };  
  19. class Child2:public Base  
  20. {  
  21.     void print()  
  22.     {  
  23.         cout<<"我是Child2类"<<endl;  
  24.     }  
  25. };  
  26. /*如果容器中函数的对象是不同类的,那么这时候用使用多态是非常的方便的*/  
  27. void function(const vector<Base*>&V)  
  28. {  
  29.     for(int i=0;i<V.size();++i)  
  30.     {  
  31.         V.at(i)->print();  
  32.     }  
  33. }  
  34.   
  35. /*静态多态,使用模板*/  
  36. template<typename T>  
  37. void TempalteFuncion(const vector<T*>&V)  
  38. {  
  39.     for(int i=0;i<V.size();++i)  
  40.     {  
  41.         V.at(i)->print();  
  42.     }  
  43. }  
  44. void main()  
  45. {  
  46.     /*虚函数多态  模板多态混用*/  
  47.     Child1 child1;  
  48.     Child2 child2;  
  49.     Base *p;  
  50.     p=&child1;  
  51.     p->print();  
  52.     p=&child2;  
  53.     p->print();  
  54.     vector<Base*>BaseVector;  
  55.     BaseVector.push_back(&child1);  
  56.     BaseVector.push_back(&child2);  
  57.     function(BaseVector);  
  58.          TempalteFuncion(BaseVector);  
  59. }  

 

总结(摘)

动态多态只需要一个多态函数,生成的可执行代码尺寸较小,静态多态必须针对不同的类型产生不同的模板实体,尺寸会大一些,但生成的代码会更快,因为无需通过指针进行间接操作。静态多态比动态多态更加类型安全,因为全部绑定都被检查于编译期。正如前面例子所示,你不可将一个错误的类型的对象插入到从一个模板实例化而来的容器之中。此外,正如你已经看到的那样,动态多态可以优雅地处理异质对象集合,而静态多态可以用来实现安全、高效的同质对象集合操作。 

静态多态为C++带来了泛型编程(generic programming)的概念。泛型编程可以认为是“组件功能基于框架整体而设计”的模板编程。STL就是泛型编程的一个典范。STL是一个框架,它提供了大量的算法、容器和迭代器,全部以模板技术实现。从理论上讲,STL的功能当然可以使用动态多态来实现,不过这样一来其性能必将大打折扣。  

静态多态还为C++社群带来了泛型模式(generic patterns)的概念。理论上,每一个需要通过虚函数和类继承而支持的设计模式都可以利用基于模板的静态多态技术(甚至可以结合使用动态多态和静态多态两种技术)而实现。正如你看到的那样,Andrei Alexandrescu的天才作品Modern C++ Design: Generic Programming and Design Patterns Applied(Addison-Wesley)和Loki程序库已经走在了我们的前面。

C++中的多态(Polymorphism)是指在父类和子类之间的相互转换,以及在不同对象之间的相互转换。 C++中的多态性有两种:静态多态和动态多态。 1. 静态多态 静态多态是指在编译时就已经确定了函数的调用,也称为编译时多态C++中实现静态多态的方式主要有函数重载和运算符重载。 函数重载是指在同一作用域内定义多个同名函数,但它们的参数列表不同。编译器根据传递给函数的参数类型和数量来确定调用哪个函数。例如: ```c++ void print(int num) { std::cout << "This is an integer: " << num << std::endl; } void print(double num) { std::cout << "This is a double: " << num << std::endl; } int main() { int a = 10; double b = 3.14; print(a); // 调用第一个print函数 print(b); // 调用第二个print函数 } ``` 运算符重载是指对C++中的运算符进行重新定义,使其能够用于自定义的数据类型。例如: ```c++ class Complex { public: Complex(double real, double imag) : m_real(real), m_imag(imag) {} Complex operator+(const Complex& other) const { return Complex(m_real + other.m_real, m_imag + other.m_imag); } private: double m_real; double m_imag; }; int main() { Complex a(1.0, 2.0); Complex b(3.0, 4.0); Complex c = a + b; // 调用Complex类中重载的+运算符 } ``` 2. 动态多态 动态多态是指在运行时根据对象的实际类型来确定调用哪个函数,也称为运行时多态C++中实现动态多态的方式主要有虚函数和纯虚函数。 虚函数是在父类中定义的可以被子类重写的函数,使用virtual关键字声明。当一个对象的指针或引用指向一个子类对象时,调用虚函数时会根据实际的对象类型来确定调用哪个函数。例如: ```c++ class Shape { public: virtual void draw() { std::cout << "Drawing a shape." << std::endl; } }; class Circle : public Shape { public: void draw() override { std::cout << "Drawing a circle." << std::endl; } }; int main() { Shape* shape_ptr = new Circle(); shape_ptr->draw(); // 调用Circle类中重写的draw函数 } ``` 纯虚函数是在父类中定义的没有实现的虚函数,使用纯虚函数声明(如virtual void func() = 0;)。父类中包含纯虚函数的类称为抽象类,抽象类不能被实例化,只能作为基类来派生子类。子类必须实现父类的纯虚函数才能实例化。例如: ```c++ class Shape { public: virtual void draw() = 0; }; class Circle : public Shape { public: void draw() override { std::cout << "Drawing a circle." << std::endl; } }; int main() { Shape* shape_ptr = new Circle(); shape_ptr->draw(); // 调用Circle类中重写的draw函数 } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值