C++ 动多态 vs 静多态

 


《c++ templates, chapter14》


Summary

术 语:

---通过继承实现的多态是 绑定的  和  动态的。

绑定指: 各个子类的接口需要与公共基类的虚函数相同。 有时,也把绑定这个概念称为入侵的或插入的。

动态指: 接口的绑定是在运行期完成的。用基类的指针去调用哪个子类的虚函数呢,运行时才确定;

 

---通过模板实现的多态是 非绑定的 和 静态的

非绑定指: 不需要基类提供公共的接口。

静态指: 接口的绑定是在编译期完成的,即在编译器确定调用的哪个类的哪个具体的函数。
 

在其他语言中,还可能会有其他组合存在,例如smalltalk提供了非绑定的动态多态。

 

-----优点和缺点:

c++动态多态的优点:

# 能够优雅地处理异类集合;

# 可执行代码通常比较小(因为对于静多态而言,为处理不同的类型必须生成多个不同的模板实例。例如,下面的myDraw(const GeoObj& obj)函数,对于动态多态而言,

  只需要一份函数,但是对于静态多态而言,需要根据调用情况,生成myDraw_t<Line_t>, myDraw_t<Circle_t>等多份函数。)

 

c++静态多态的优点:

@ 代码效率较高,因为相比动态多态,其不存在通过指针的间接引用;

@ 具有更好的类型安全性,因为静多态会对所有的绑定操作进行检查。

缺陷:使用静多态后,再也不能透明地处理异类的集合;所有的类型都必须在编译期间确定;


动多态

基类的指针指向子类对象,实现虚函数的动态绑定。

对于动态多态,相当引人注目的一个特点是处理异类容器的能力! 如下的drawElems函数。

//base calss
class GeoObj {
public:
    virtual void draw() const = 0;
    virtual float centerX_of_gravity() const = 0;

};
class Circle :public GeoObj {
public:
    virtual void draw() const override
    {
        cout << "draw Circle\n";
    }
    virtual float centerX_of_gravity() const override {
        cout << "Called  Circle::centerX_of_gravity" << endl;
        return 0.f;
    }
};

class Line :public GeoObj {
public:
    virtual void draw() const override
    {
        cout << "draw Line\n";
    }
    virtual float centerX_of_gravity() const override {
        cout << "Called  Line::centerX_of_gravity" << endl;
        return 0.f;
    }
};

客户端代码:

void myDraw(const GeoObj& obj) {
    obj.draw();
}

float distanceOfX(const GeoObj& obj1, const GeoObj& obj2) {
    float disX =  obj1.centerX_of_gravity() - obj2.centerX_of_gravity();
    return std::fabs(disX);
}

//处理异类集合
void drawElems(const vector<GeoObj*>& elems) {
    for (const auto& it: elems) {
        it->draw();
    }
}
int main() {
    Line line;
    Circle c, c1, c2;
    myDraw(line);
    myDraw(c);
    distanceOfX(line, c1);

    vector<GeoObj*> elemsVec;
    elemsVec.push_back(&line);
    elemsVec.push_back(&c1);
    elemsVec.push_back(&c2);
    drawElems(elemsVec);
    return 0;
}

 


静多态

模板也能用于实现多态,这种多态不依赖于基类的存在 (动态多态需要在基类中声明公共的函数接口)。

这种多态的“公共性”体现在各个不同的类都需要支持某些公共的函数接口。另外,各个类之间是相互独立的哦

//具体的几何类。没有派生自其它任何类
class Circle_t {
public:
    void draw() const
    {
        cout << "draw Circle\n";
    }
    float centerX_of_gravity() const {
        cout << "Called  Circle_t::centerX_of_gravity" << endl;
        return 0.f;
    }
};

class Line_t {
public:
    void draw() const
    {
        cout << "draw Line\n";
    }
    float centerX_of_gravity() const {
        cout << "Called  Line_t::centerX_of_gravity" << endl;
        return 0.f;
    }
};

class Check_t {
public:
    void drawError() const
    {
        cout << "draw Line\n";
    }
};

客户端的使用:

template <class T>
void myDraw_t(const T& obj) {
    obj.draw();
}

template <class T1, typename T2>
float distanceOfX_t(const T1& obj1, const T2& obj2) {
    float disX = obj1.centerX_of_gravity() - obj2.centerX_of_gravity();
    return std::fabs(disX);
}

//只能将同类对象放到一个容器中:
template<class T>
void drawElems_t(const vector<T*>& elems) {
    for (const auto& it : elems) {
        it->draw();
    }
}


int main() {
    Line_t line;
    Line_t line1;
    myDraw_t(line); //编译器检测到该行后,会生成一个函数实例myDraw_t<Line_t>

    Circle_t c1;
    Circle_t c2;
    myDraw_t(c1); //编译器检测到该行后,会生成一个函数实例myDraw_t<Circle_t>

    distanceOfX_t(line,c1);//编译器检测到该行后,会生成一个函数实例distanceOfX_t<Line_t, Circle_t>

    vector<Line_t*> vect;
    vect.push_back(&line);
    vect.push_back(&line1);
    //vect.push_back(&c1); 不能酱Circle_t的对象放进去哦
    drawElems_t(vect);

    //Check_t checkObj;
    //myDraw_t(checkObj);//编译期间就可以检查出draw函数不是Check_t类的成员函数。

    return 0;
}

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

First Snowflakes

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值