C++小结:多态(2) --类别与实现、动态多态

多      态

     1、动态多态的实现原理

    2、多态的类别及实现方法

    3、动态多态的四种情况

(2)多态的类别及实现方法

2.1 静态多态:编译时多态、函数的多态性,重载、模板、宏

2.2 动态多态:运行时多态、类的多态性,继承和虚函数,晚绑定、动态绑定 

2.3 封装可以使得代码模块化,继承可以扩展已存在的代码,他们的目的都是为了代码重用。而多态的目的则是为了接口重用。也就是说,不论传递过来的究竟是哪个类的对象,函数都能够通过同一个接口调用到适应各自对象的实现方法。

(3)动态多态的四种情况

3.1 用一个父类的指针指向一个子类对象

3.2 用一个父类的指针当函数的形参,用这个指针可以接受到任何它的子类对象也包括他自己

3.3 在复合类,尽量饮用高层次的类(父类的指针)当做类的成员变量,这样就可以通过它创建出它所对应的任何子类对象包括他自己

3.4 在容器中,可以声明一个父类指针的容器,这时可以往容器中添加它所对应的任何子类对象包括他自己

动态多态和静态多态的比较
静态多态
优点:
由于静多态是在编译期完成的,因此效率较高,编译器也可以进行优化;
有很强的适配性和松耦合性,比如可以通过偏特化、全特化来处理特殊类型;
最重要一点是静态多态通过模板编程为C++带来了泛型设计的概念,比如强大的STL库。
缺点:
由于是模板来实现静态多态,因此模板的不足也就是静多态的劣势,比如调试困难、编译耗时、代码膨胀、编译器支持的兼容性
不能够处理异质对象集合
动态多态
优点:
OO设计,对是客观世界的直觉认识;
实现与接口分离,可复用
处理同一继承体系下异质对象集合的强大威力
缺点:
运行期绑定,导致一定程度的运行时开销;
编译器无法对虚函数进行优化
笨重的类继承体系,对接口的修改影响整个类层次;
不同点:
本质不同,静态多态在编译期决定,由模板具现完成,而动态多态在运行期决定,由继承、虚函数实现;
动态多态中接口是显式的,以函数签名为中心,多态通过虚函数在运行期实现,静态多台中接口是隐式的,以有效表达式为中心,多态通过模板具现在编译期完成
相同点:
都能够实现多态性,静态多态/编译期多态、动态多态/运行期多态;
都能够使接口和实现相分离,一个是模板定义接口,类型参数定义实现,一个是基类虚函数定义接口,继承类负责实现

//这里隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

//1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。

//2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

//上面的程序中:

//1)函数Derived::f1(float)覆盖了Base::f1(float)

//2)函数Derived::f2(int)隐藏了Base::f2(float),而不是重载。

//3)函数Derived::f3(float)隐藏了Base::f3(float),而不是覆盖


A、动态多态
#ifndef __C__No807Class__Father__
#define __C__No807Class__Father__

#include <iostream>
using namespace std;
class Father
{
public:
    virtual void print();
};
#endif /* defined(__C__No807Class__Father__) */

#include "Father.h"
void Father::print()
{
    cout << "Father print" << endl;
}

#ifndef __C__No807Class__Son__
#define __C__No807Class__Son__

#include <iostream>
#include "Father.h"
class Son : public Father
{
public:
    void print();
};
#endif /* defined(__C__No807Class__Son__) */

#include "Son.h"
void Son::print()
{
    cout << "Son print" << endl;
}

#ifndef __C__No807Class__Son2__
#define __C__No807Class__Son2__

#include <iostream>
#include "Father.h"
class Son2 : public Father
{
public:
    void print();
};

#endif /* defined(__C__No807Class__Son2__) */

#include "Son2.h"
void Son2::print()
{
    cout << "Son2 print" << endl;
}

#include <iostream>
#include<string>
#include<vector>
#include "Son.h"
#include "Son2.h"
//如果容器中函数的对象是不同类的,那么这时候用使用多态是非常的方便的
void func(const vector<Father*>&V)  //容器中,可以声明一个父类指针的容器,可以往这个容器中添加它所对应的任何子类对象包括他自己
{
    for(int i = 0; i < V.size(); ++i)
    {
        V.at(i) -> print();
    }
}
void foo(Father &f)  //父类指针当函数形参,用这个指针可以接受到任何它的子类对象也包括他自己
{
    f.print();  //Son,不加引用Father
}

int main()
{
    Son s;
    Son2 s2;
    Father f;
    Father *p;
    p = &s;    //父类指针指向子类对象
    p -> print();
    p = &s2;
    p -> print();
    foo(s);
    vector<Father*>FatherVector;
    FatherVector.push_back(&s);
    FatherVector.push_back(&s2);
    FatherVector.push_back(&f);
    func(FatherVector);  
    return 0;
}

B、静态多态--重载
函数重载,使用相同的函数名,但是函数参数列表不同,(参数类型或个数),用这种方法来实现多态。函数重载和模板就多态来讲其实是一样的,只不过是重载函数要写多个函数,而模板的话我们使用typedef,只要写一个函数,在调用的时候,会根据参数的类型自己去替换匹配而已。
#include <iostream>
#include <string>
using namespace std;
int add (int num1, int num2)
{
    return (num1 + num2);
}
int add (int num1, string str1)
{
    return (num1 + atoi(str1.c_str()));  //把字符串的数字转为数字型的数值
}
int add (int num1, char c1)
{
    return (num1 + c1);
}
int main()
{
    int n1 = 10, n2 = 20;
    string s1 = "30";
    char c1 = 'a';
    cout << n1 << " + " << n2 << " = " << add(n1, n2) <<endl;
    cout << n1 << " + " << s1 << " = " << add(n1, s1) <<endl;
    cout << n1 << " + " << c1 << " = " << add(n1, c1) <<endl;
    return 0;
}

C、静态多态--模板
template <typename T>
T max(const T& i, const T& j) 
{
       return (i > j) ? i : j;
}
//返回两个任意类型对象的最大值(对象),前提是该类型能够使用>运算符进行比较,并且返回值是bool类型。
使用:
int a = 3; int b = 4;
cout << max(a, b) << endl;
float c = 2.4; float d = 1.2;
cout << max(c, d) << endl;
输出结果为:
         4
        2.4
这种绑定发生在编译期,这是由于模板的实例化是发生在编译期的,即在编译时编译器发现你调用max(a, b)时就自动生成一个函数
int max(const int& i, const int& j) 
{
       return (i > j) ? i : j;
}
即将所有的T替换成int;
当你调用max(c, d)时就自动生成一个函数
float max(const float& i, const float& j)
{
        return (i > j) ? i : j;
}
模板2
#include<iostream>
#include<string>
#include<vector>
using namespace std;
/*虚函数机制*/
class Base
{
public:
    virtual void print()=0;
};

class Child1:public Base
{
    void print()
    {
        cout<<"我是Child1类"<<endl;
    }
};
class Child2:public Base
{
    void print()
    {
        cout<<"我是Child2类"<<endl;
    }
};
/*如果容器中函数的对象是不同类的,那么这时候用使用多态是非常的方便的*/
void func(const vector<Base*>&V)
{
    for(int i=0;i<V.size();++i)
    {
        V.at(i)->print();
    }
}

/*静态多态,使用模板*/
template<typename T>
void TempalteFuncion(const vector<T*>&V)
{
    for(int i=0;i<V.size();++i)
    {
        V.at(i)->print();
    }
}
int main()
{
    /*虚函数多态  模板多态混用*/
    Child1 child1;
    Child2 child2;
    Base *p;
    p=&child1;
    p->print();
    p=&child2;
    p->print();
    vector<Base*>BaseVector;
    BaseVector.push_back(&child1);
    BaseVector.push_back(&child2);
    func(BaseVector);
    TempalteFuncion(BaseVector);
    
    return 0;
}
D、静态多态--宏多态(忽略)
#include<iostream>  
#include<string>  
using namespace std;  
  
#define ADD(A,B) ((A)+(B))  
  
void main()  
{  
    /*宏多态*/  
    int num1=10;  
    int num2=20;  
    string str1="22";  
    string str2="33";  
    cout<<"宏多态 ADD(A+B) A+B:"<<ADD(num1,num2)<<endl;  
    cout<<"宏多态 ADD(A+B) A+B:"<<ADD(str1,str2)<<endl;  
}  

E、子类指针指向父类对象、隐藏
#include <iostream>
using namespace std;
class A
{
public:
    void f1()
    {
        cout << "1" << endl;
    }
    virtual void f2()
    {
        cout << "2" << endl;
    }
};
class B : public A
{
public:
    void f1()
    {
        cout << "3" << endl;
    }
    void f2()
    {
        cout << "4" << endl;
    }
};
int main()
{
    A a;
    B b;
    A *p = &a;
    p -> f1();  //1
    p -> f2();  //2
    p = &b;
    p -> f1();  //1
    p -> f2();  //4
    B *ptr = (B *)&a;  //子类指针ptr,父类对象a的引用强制转化为B类类型指针
    ptr -> f1();  //3
    ptr -> f2();  //2
    
    return 0;
}
#include <iostream>
using namespace std;
class Base
{
public:
    virtual void f1(float x)
    {
        cout << "Base f1 (float) = " << x << endl;
    }
    void f2(float x)
    {
        cout << "Base f2 (float) = " << x << endl;
        }
    void f3(float x)
    {
        cout << "Base f3 (float) = " << x << endl;
    }
};
class Derived : public Base
{
public:
    void f1(float x)
    {
        cout << "Derived f1 (float) = " << x << endl;  //覆盖,多态
    }
    void f2(int x)
    {
        cout << "Derived f2 (float) = " << x << endl;  //隐藏
    }
    void f3(float x)
    {
        cout << "Derived f3 (float) = " << x << endl;  //隐藏
    }
};
int main()
{
    Derived d;
    Base *pb = &d;
    Derived *pd = &d;
    
    pb -> f1(3.14f);  //D f1
    pd -> f1(3.14f);  //D f1
    
    pb -> f2(3.14f);  //B f2
    pd -> f2(3.14f);  //D f2
    
    pb -> f3(3.14f);  //B f3
    pd -> f3(3.14f);  //D f3
    
    return 0;
}
//这里“隐藏”是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
//(1)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)。
//(2)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。
//上面的程序中:
//(1)函数Derived::f1(float)覆盖了Base::f1(float)。
//(2)函数Derived::f2(int)隐藏了Base::f2(float),而不是重载。
//(3)函数Derived::f3(float)隐藏了Base::f3(float),而不是覆盖

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值