C/C++教程

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>

 

综上,

  • 使用non-virtual interface手法,那是一种Template Method的一种特殊形式。它以public non-virtual成员函数包裹较低访问性的virtual函数;
  • 将virtual函数替换为函数指针成员变量,这是Strategy的一种表现手法;
  • 以std::function成员变量替换virtual函数,因而允许使用任何可调用物搭配一个兼容于需求的签名式,这也是Strategy的一种形式;
  • 将继承体系内的virtual函数替换为另一个继承体系内的virtual函数,这是传统Strategy的一种实现手法。
这篇关于Effective C++ 总结[条款35 考虑virtual函数以外 的其他选择]的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!