这是一个混合,可以用c ++完成吗?

Sid*_*Bob 5 c++ inheritance templates mixins

我有自己的数组类模板,我想可选择添加功能.

作为功​​能的一个例子,采用多线程支持:在某些情况下,我需要放在#pragma omp atomic任何更新代码之前的数组(强制执行原子行为的编译器指令,细节并不重要).在其他情况下,我需要不这样做的数组,因为我知道它们只会安全更新,我需要避免性能损失.

直觉上应该可以定义一个AtomicUpdates我可以继承的类.因此,为了定义一个带有原子更新的双数组,我会说类似的东西

class AtomicDoubleArray : public MyArray<double>, public AtomicUpdates {};
Run Code Online (Sandbox Code Playgroud)

但是我看不出你在实践中如何实现它,这也会破坏继承接口的原则,而不是实现.

任何人都可以告诉我我真正想做的事情吗?

Bow*_*ens 5

即使你最终没有使用它们,现在mixins和策略模板参数是非常有用的东西要理解.在这种情况下,它们非常相似.首先,一个带有mixin base的数组.我使用过c ++ 0x互斥体而不是openmp但你应该明白这个想法.

#include <iostream>
#include <vector>
#include <mutex>

template <class value_t, class base_t>
class array_t : private base_t {
    std::vector<value_t> v_;
public:
    array_t(size_t sz = 0) : v_ (sz) { }
    value_t get(size_t i) const
    {
        this->before_get();
        value_t const result = v_[i];
        this->after_get();
        return result;
    }
    void set(size_t i, value_t const& x)
    {
        this->before_set();
        v_[i] = x;
        this->after_set();
    }
};

class no_op_base_t {
protected:
    void before_get() const { }
    void after_get() const { }
    void before_set() const { }
    void after_set() const { }
};

class lock_base_t {
    mutable std::mutex m_;
protected:
    void before_get() const { std::cout << "lock\n"; m_.lock(); }
    void after_get() const { std::cout << "unlock\n"; m_.unlock(); }
    void before_set() const { std::cout << "lock\n"; m_.lock(); }
    void after_set() const { std::cout << "unlock\n"; m_.unlock(); }

};

int main()
{
    array_t<double, no_op_base_t> a (1);
    array_t<double, lock_base_t> b (1);
    std::cout << "setting a\n";
    a.set(0, 1.0);
    std::cout << "setting b\n";
    b.set(0, 1.0);
    std::cout << "getting a\n";
    a.get(0);
    std::cout << "getting b\n";
    b.get(0);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

现在是同一个类但使用策略参数方法而不是继承.

#include <iostream>
#include <vector>
#include <mutex>

template <class value_t, class policy_t>
class array_t {
    policy_t policy_;
    std::vector<value_t> v_;
public:
    array_t(size_t sz = 0) : v_ (sz) { }
    value_t get(size_t i) const
    {
        policy_.before_get();
        value_t const result = v_[i];
        policy_.after_get();
        return result;
    }
    void set(size_t i, value_t const& x)
    {
        policy_.before_set();
        v_[i] = x;
        policy_.after_set();
    }
};

class no_op_base_t {
public:
    void before_get() const { }
    void after_get() const { }
    void before_set() const { }
    void after_set() const { }
};

class lock_base_t {
    mutable std::mutex m_;
public:
    void before_get() const { std::cout << "lock\n"; m_.lock(); }
    void after_get() const { std::cout << "unlock\n"; m_.unlock(); }
    void before_set() const { std::cout << "lock\n"; m_.lock(); }
    void after_set() const { std::cout << "unlock\n"; m_.unlock(); }

};

int main()
{
    array_t<double, no_op_base_t> a (1);
    array_t<double, lock_base_t> b (1);
    std::cout << "setting a\n";
    a.set(0, 1.0);
    std::cout << "setting b\n";
    b.set(0, 1.0);
    std::cout << "getting a\n";
    a.get(0);
    std::cout << "getting b\n";
    b.get(0);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下两者都非常相似.mixin的重要区别在于mixin可以定义一些虚拟方法,并允许您通过继承来改变数组的行为.如下所示:

template <class value_t>
class mk_virtual_base_t {
protected:
    void before_get() const { }
    void after_get() const { }
    void before_set() const { }
    void after_set() const { }

    virtual value_t get(size_t) const = 0;
    virtual void set(size_t, value_t) = 0;
};

template <class value_t>
class daily_wtf_contender_t : public array_t<value_t, mk_virtual_base_t<value_t> > {
    virtual value_t get(size_t) const { std::cout << "surprise! get is virtual!\n"; return 0; }
    virtual void set(size_t, value_t) { std::cout << "surprise! set is virtual!\n"; }
};
Run Code Online (Sandbox Code Playgroud)

虽然有一些真实情况下mixin的优势很有用,但并不常见.因此,在使用模板时,策略方法通常更合适.标准库在许多地方使用策略参数,因此有一些很好的例子供您学习.

至于你关于"继承接口,而不是实现"的问题.使用仔细继承实现是非常有用的.多重继承也是如此.您只需要明智地了解何时使用它们.