编程语言
首页 > 编程语言> > Effective C++ 总结[条款35 考虑virtual函数以外 的其他选择]

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

作者:互联网

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

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>

 

综上,

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