Sid*_*Bob 5 c++ inheritance templates mixins
我有自己的数组类模板,我想可选择添加功能.
作为功能的一个例子,采用多线程支持:在某些情况下,我需要放在#pragma omp atomic
任何更新代码之前的数组(强制执行原子行为的编译器指令,细节并不重要).在其他情况下,我需要不这样做的数组,因为我知道它们只会安全更新,我需要避免性能损失.
直觉上应该可以定义一个AtomicUpdates
我可以继承的类.因此,为了定义一个带有原子更新的双数组,我会说类似的东西
class AtomicDoubleArray : public MyArray<double>, public AtomicUpdates {};
Run Code Online (Sandbox Code Playgroud)
但是我看不出你在实践中如何实现它,这也会破坏继承接口的原则,而不是实现.
任何人都可以告诉我我真正想做的事情吗?
即使你最终没有使用它们,现在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的优势很有用,但并不常见.因此,在使用模板时,策略方法通常更合适.标准库在许多地方使用策略参数,因此有一些很好的例子供您学习.
至于你关于"继承接口,而不是实现"的问题.使用仔细继承实现是非常有用的.多重继承也是如此.您只需要明智地了解何时使用它们.