EffectiveC++学习笔记-条款34|35

条款34 区分接口继承和实现继承
条款35 考虑virtual函数以外的选择

区分接口继承和实现继承

在设计类成员函数时,一般既不要将所有函数都声明为non-virtual(普通函数),这会使得没有余裕空间进行特化工作;也一般不要将所有函数都声明为virtual(虚函数或纯虚函数),因为一般会有一些成员函数是基类就可以决定下来的,而被所有派生类所共用的。这个设计法则并不绝对,要视实际情况来定。

总结
  1. 接口继承和实现继承不同。在public继承之下,derived class总是继承base class的接口;
  2. pure virtual函数只具体指定接口继承;
  3. impure virtual函数具体指定接口继承和缺省实现继承;
  4. non-virutal函数具体指定接口继承以及强制性实现继承。

考虑virtual函数以外的选择

使用non-virtual interface的方式实现Template Method模式

直接上代码:

class Base
{
public:
    virtual void work() const  //work
    {
        cout <<"Base::work"<<endl;
        dowork();
    }

private:
    //具体的work  子类需要实现自己的dowork() 以便 work()函数调用
    //子类不实现默认调用 Base的dowork()
    virtual int dowork() const
    {
        cout <<"Base do work"<<endl;
    }
};

class Derived: public Base
{
public:

private:
    virtual int dowork() const
    {
        cout <<"Derived do work "<<endl;
    }
};

int main(int argc, char *argv[])
{
    Derived d;
    d.work();
    return 0;
}
//打印结果
Base::work
Derived do work

显然不重写dowork函数是调用父类的函数。这种方法和“钩子方法“使用的原理是差不多的。
这个函数也被称为virtual函数的外覆器(wrapper)。

使用function pointers的方式实现Strategy模式

例如在设计一个游戏角色的健康成长设置的时候。我们可以直接指向一个健康计算函数,可直接调用函数进行计算

class GameCharacter;

//缺省的健康计算 (正常人)  还可能有体力好的人 恢复健康就很快等等
int defaultHealthCalc(GameCharacter&);

class GameCharacter
{
public:
    typedef int (*healthCalcFunc)(GameCharacter& gc);
    explicit GameCharacter(healthCalcFunc hcf = defaultHealthCalc) : m_hcf(hcf){}

    //获取一个角色的健康值
    int healthValue() const
    {
        return m_hcf(*this);
    }

private:
    healthCalcFunc m_hcf;
};

这样使用函数指针的方式,弹性就更大了。
我们的子类可以继承这个类:

class Guy : public GameCharacter
{
public:
    explicit Guy(healthCalcFunc hcf = defaultHealthCalc):GameCharacter(hcf){}
    ...
};

//提供不同体质的人的计算方法
int loseHealthQuickly(const GameCharacter&);
int loseHealthSlowly(const GameCharacter&);

//可以创建不同体质的人
Guy g1(loseHealthQuickly);
Guy g2(loseHealthSlowly);

当然可以提供函数设置这个函数指针。

但是这样还是有问题,当我们需要使用non-member函数访问class的non-public成份的唯一方法就是弱化封装。

使用tr1::function的方式实现Strategy模式

使用函数指针的约束很明显,必须是函数,固定的返回值与参数。但是tr1::function则没有这些现实,这样的对象可持有任何可调用物(函数指针、函数对象、成员函数指针),只要声明格式兼容与需求。
只需要将上面类的函数指针声明替换成:

typedef std::tr1:;function<int(const GameCharacter&)>  HealthCalcFunc;

举个简单例子:

void func(string str)//带调用的函数
{
    qDebug() <<"func:"<<str;
}

struct Func//函数对象
{
    void operator ()(string str)
    {
        qDebug() <<"Func:operator:"<<str;
    }
};

std::function<void(string str)> pfunc;//声明

int main(int argc, char *argv[])
{
    pfunc = func;
    pfunc("hello");

    Func f;
    pfunc = f;
    pfunc("world");

    return 0;
}
//打印结果
func:hello
Func:operator:world
常见的Strategy模式

这个想必都很熟悉了,实现比较简单,但是呢始终不如tr1::funtion和tr1::bind酷。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值