您的位置:首页 > 编程语言 > C语言/C++

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

2017-07-13 11:34 330 查看
条款34 区分接口继承和实现继承

条款35 考虑virtual函数以外的选择

区分接口继承和实现继承

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

总结

接口继承和实现继承不同。在public继承之下,derived class总是继承base class的接口;

pure virtual函数只具体指定接口继承;

impure virtual函数具体指定接口继承和缺省实现继承;

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酷。。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息