effective stl 第38条:遵循按值传递的原则来设计函数子类

无论是C还是C++,都不允许将一个函数传递给另一个函数,相反,你必须使用函数指针,qsort函数就是这样的一个函数。

void qsort(void* base, size_t nmemb, size_t size, int(*cmpfcn)(const void* a, const void *b));

qsort是按值传递的,C++和C标准都遵循这个原则:函数指针是按值传递的。

for_each是安置传递的,其原型如下:

template<class InputIterator, class Function>
Function
for_each(InputIterator first, InputIterator last, Function f);//按值传递past-by-value
#include<iostream>
#include<vector>
#include<algorithm>

using namespace std;

class Dosomething :public unary_function<int, void>{
public:
    void operator()(int x){};
};

int main()
{
    typedef vector<int>::iterator IntIterator;
    vector<int> di;
    Dosomething d;//创建一个函数对象
    //用类型参数dequeInerator和Dosomething&来调用for_each,这将强制d按照引用传递并返回
    for_each<IntIterator, Dosomething&>(di.begin(), di.end(), d);
    return 0;
}

但是STL的使用者几乎从来不会做这样的事情,而且,如果将函数对象按照引用传递,有些算法是不能编译通过的。因此,假设函数独享总是按值传递,在实践中,这种假设几乎总是成立的。

因此这意味着两件事情:
1、函数必须尽量小。
2、函数对象必须是单态的,也就是说,他们不能使用虚函数。
这是因为,如果参数的类型是基类类型,而参数类型确实派生类类型,那么在传递的过程中会产生剥离问题:在对象被复制过程中,派生部分可能会被去掉,而仅仅保留基类部分。

解决方法:
将所需的数据和虚函数从函数子类中分离出来,放到一个新的类中,然后在函数子类中包含一个指针,指向这个新类的对象,例如:如果你希望创建一个包含大量数据并且使用多态性的含数子类:

template<typename T>
class BPFC :public unary_function<T, void>{//BPFC=big polymorphic Function class
private:
    float a;
    int x;
public:
    virtual void operator()(const T& val)const;//这是一个虚函数,所以存在剥离问题
};

那么就应该创建一个小巧的、单态的类,其中包含一个指针,指向一个实现类,并且将所有的数据和虚函数都放在实现类中:

template<typename T>
class BPFCImpl :public unary_function<T, void>{
private:
    float a;//原来BPFC中的数据
    int x;
    virtual ~BPFCImpl();//多态类需要虚析构函数
    virtual void operator()(const T& val)conat;
    friend class BPFC<T>;//允许BPFC访问内部数据
};

template<typename T>
class BPFC :public unary_function<T, void>{
private:
    BPFCImpl<T> *pImpl;
public:
    void operator()(const T& val)const
    {
        pImpl->operator()(val);
    }
};

从STL的角度看,需要牢记的是,如果函数子类用到了这项技术,那么它必须以某种合理的方式来支持拷贝动作,如果你是上述BPFC类的作者,那么你必须确保BPFC的拷贝函数正确处理了它所指向的BPFCImpl对象,也许最简单而合理的做法是使用引用计数,可以使用类似于BOOST的shared_ptr这样的辅助类。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值