ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Effective C++ 总结[条款35 考虑virtual函数以外 的其他选择]

2022-05-04 18:04:25  阅读:151  来源: 互联网

标签:lottery Effective void 35 class BaseTraveller virtual public


假设写一个原神抽奖的函数,将玩家分为普通玩家、微氪玩家、氪金狂魔等,以下是所有类的基类:

class BaseTraveller {
public:
    virtual void lottery(int num);
};

其他玩家分类都可以重写该抽奖函数,以提供不同的抽奖算法。这是用virtual函数来实现的,现在本条款介绍了几种虚函数以外的实现方法。

1.藉由Non-Virtual Interface手法实现Template Method模式

首先介绍一下什么是Template Method模式(跟c++的模板template一点关系也没有哦, 是一种设计模式)。

Template Method,定义一个操作中算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的特定部分。

在此例中,算法的骨架就是lottery中的结构,它内部调用了doLottery这个核心部分,而子类可以重载这个部分使得抽奖算法在子类中表现出不同。

class BaseTraveller {
public:
    void lottery(int num);

private:
    virtual void doLottery();
};

class LittleRMBTraveller : public BaseTraveller {
private:
    virtual void doLottery();
};

class MuchRMBTraveller : public BaseTraveller {
private:
    virtual void doLottery();
};

// BaseTraveller
void BaseTraveller::lottery(int num)
{
    // do init
    doLottery();
    // do exit
}

void BaseTraveller::doLottery()
{
    // default method
}

// LittleRMBTraveller
void LittleRMBTraveller::doLottery()
{
    // more lucky method
}

// MuchRMBTraveller
void MuchRMBTraveller::doLottery()
{
    // unlucky method
}

// main.cpp
BaseTraveller* pMuchRMB = new MuchRMBTraveller;
pMuchRMB->lottery(10);

2.藉由函数指针实现Strategy模式

首先我介绍一下传统的Strategy设计模式。定义一系列算法,把它们封装为一个个单独的类,并且使他们可以相互替换。

class Lottery {
    // normal method
public:
    virtual void doLottery(int) { };
};

class LuckyLottery : public Lottery {
    // lucky method
public:
    virtual void doLottery(int) { };
};

class UnluckyLottery : public Lottery {
    // unlucky method
public:
    virtual void doLottery(int) { };
};

class BaseTraveller {
public:
    BaseTraveller(Lottery* p) 
        : pLty(p) 
    { 
    };
    void lottery(int num) { pLty->doLottery(num); }
private:
    Lottery* pLty;
};

class LittleRMBTraveller : public BaseTraveller {
public:
    LittleRMBTraveller(Lottery* p)
        : BaseTraveller(p)
    {
    }

};

class MuchRMBTraveller : public BaseTraveller {
public:
    MuchRMBTraveller(Lottery* p)
        : BaseTraveller(p)
    {
    }
};

// main.cpp
LittleRMBTraveller littleRMB(new LuckyLottery);
littleRMB.pLty->lottery(10);

以上是一个传统Strategy模式的一个例子,可以通过在构造函数中传入不同的抽奖算法,使得对于不同类别的旅行者有不同的行为。

那么现在进入正题,由一个函数指针来实现Strategy模式。

class BaseTraveller;
void normalLottery(int num, BaseTraveller& bt) { };
void luckyLottery(int num, BaseTraveller& bt) { };
void unluckyLottery(int num, BaseTraveller& bt) { };

class BaseTraveller {
public:
    typedef void(*pLottery)(int, BaseTraveller&);
    BaseTraveller(pLottery lty)
        : _lottery(lty)
    {

    }
    void lottery(int num) { _lottery(num, *this); }
private:
    pLottery _lottery;
};

class LittleRMBTraveller : public BaseTraveller {
public:
    LittleRMBTraveller(pLottery lty)
        : BaseTraveller(lty)
    {

    }
};

class MuchRMBTraveller : public BaseTraveller {
public:
    MuchRMBTraveller(pLottery lty)
        : BaseTraveller(lty)
    {

    }
};

// main.cpp
BaseTraveller* pLittleRMB = new LittleRMBTraveller(luckyLottery);
pLittleRMB->lottery(10);

在构造函数中传入不同的算法函数,就可以实现不同的行为。

3.藉由std::function实现Strategy模式

与函数指针相比,std::function更具有弹性,它可以接受函数指针,函数对象以及某个类的成员函数,甚至是通过隐式转换而来的以上对象都可以。

struct LuckyLottery {
    void operator() (int, BaseTraveller&) {}
};

class UnluckyBuff {
public:
    void lottery(int, BaseTraveller&) { };
};

class BaseTraveller {
public:
    typedef std::function<void(int, BaseTraveller&)> Lottery;
    BaseTraveller(Lottery lty)
        : _lottery(lty)
    {

    }
    void lottery(int num) { _lottery(num, *this); }
private:
    Lottery _lottery;
};
// 有些相同部分未列出

// main.cpp
BaseTraveller bt(normalLottery);
bt.lottery(10);

BaseTraveller* plt = new LittleRMBTraveller((LuckyLottery()));
plt->lottery(10);

UnluckyBuff unlucky;
BaseTraveller* plt2 = new MuchRMBTraveller(std::bind(&UnluckyBuff::lottery, unlucky, 10, *plt2));
plt2->lottery(1);

std::functionstd::bind需包含头文件<iostream>, <functional>

 

综上,

  • 使用non-virtual interface手法,那是一种Template Method的一种特殊形式。它以public non-virtual成员函数包裹较低访问性的virtual函数;
  • 将virtual函数替换为函数指针成员变量,这是Strategy的一种表现手法;
  • 以std::function成员变量替换virtual函数,因而允许使用任何可调用物搭配一个兼容于需求的签名式,这也是Strategy的一种形式;
  • 将继承体系内的virtual函数替换为另一个继承体系内的virtual函数,这是传统Strategy的一种实现手法。

标签:lottery,Effective,void,35,class,BaseTraveller,virtual,public
来源: https://www.cnblogs.com/strong-monkey/p/16221756.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有