在基于策略的设计中多次使用策略
multiple use of policies in policy-based design
我有一个类模板roundtrip
它采用两个策略。 只要它们不同,一切都很好,但是使用一个策略两次会导致编译错误。
例:
#include <iostream>
class walk {
protected:
void move() {
std::cout<<"i'm walking."<<std::endl;
}
};
class car {
protected:
void move() {
std::cout<<"i'm driving in a car."<<std::endl;
}
};
template<typename S, typename T>
class roundtrip : private S, private T {
public:
void printSchedule(void) {
std::cout<<"away: ";
S::move();
std::cout<<"return: ";
T::move();
}
};
int main(void){
roundtrip<walk,car> LazyTrip;
LazyTrip.printSchedule();
roundtrip<car,car> VeryLazyTrip; // ERROR: error: duplicate base type ‘walk’ invalid
VeryLazyTrip.printSchedule();
return 0;
}
如何解决这个问题?或者有更好的设计来实现相同的行为?
编辑:我在策略中添加了包装器,用户界面没有改变。 您如何看待这个解决方案,它是一个干净的设计吗?
template<typename T>
class outbound : private T {
protected:
void moveOutbound(void) {
T::move();
}
};
template<typename T>
class inbound : private T {
protected:
void moveInbound(void) {
T::move();
}
};
template<typename S, typename T>
class roundtrip : private outbound<S>, private inbound<T> {
public:
void printSchedule(void) {
std::cout<<"away: ";
this->moveOutbound();
std::cout<<"return: ";
this->moveInbound();
}
};
您可以将数据成员添加到 roundtrip
中,而不是继承,但 walk
和 car
中的函数当前protected
。如果无法将walk
和car
中的函数设为公开,则可以:
-
与
roundtrip
模板交朋友class walk { protected: void move() { std::cout<<"i'm walking."<<std::endl; } template<class T, class S> friend class roundtrip; };
-
使成员函数可通过帮助程序类
roundtrip
访问:template<typename S, typename T> class roundtrip { private: struct helperT : private T { public: // or private + friend roundtrip using T::move; using T::T; } mT; struct helperS : private S { public: using S::move; using S::S; } mS; public: void printSchedule(void) { std::cout<<"away: "; mT.move(); std::cout<<"return: "; mS.move(); } };
如果两种类型的接口相同,则可以使用帮助程序类模板而不是两个帮助程序类:
template<typename S, typename T> class roundtrip { private: template<class U> struct helper : private U { public: // or private + friend roundtrip using U::move; using U::U; }; helper<S> mS; helper<T> mT; public: void printSchedule(void) { std::cout<<"away: "; mT.move(); std::cout<<"return: "; mS.move(); } };
(也可以从帮助程序模板专用化继承,例如
class roundtrip : helperT<T>, helperS<S>
)
正如 DyP 所注意到的,这就足够了:
template<typename S, typename T>
class roundtrip {
public:
void printSchedule(void) {
std::cout<<"away: ";
awayPolicy.move();
std::cout<<"return: ";
returnPolicy.move();
}
private:
T awayPolicy;
S returnPolicy;
};
但这需要使move
方法public
。您还可以将它们设为static
和public
,因此您不需要实例字段:
class walk {
public:
static void move() {
std::cout<<"i'm walking."<<std::endl;
}
};
// the same for car
template<typename S, typename T>
class roundtrip {
public:
void printSchedule(void) {
std::cout<<"away: ";
S::move();
std::cout<<"return: ";
T::move();
}
};
您还可以考虑创建一个基类:
class travelPolicy
{
public:
virtual void move() = 0;
//...
};
从中衍生出car
和walk
。然后,roundtrip
类可以通过构造函数接受这两个策略,并通过指针在printSchedule
中使用它们。
class roundtrip
{
public:
roundtrip(
std::shared_ptr<travelpolicy> awayPolicy,
std::shared_ptr<travelpolicy> returnPolicy)
{
this->awayPolicy = awayPolicy;
this->returnPolicy = returnPolicy;
}
void printSchedule(void)
{
std::cout<<"away: ";
awayPolicy->move();
std::cout<<"return: ";
returnPolicy->move();
}
private:
std::shared_ptr<travelPolicy> awayPolicy;
std::shared_ptr<travelPolicy> returnPolicy;
};
更新(回应OP的编辑):
一般来说,您的解决方案很好,但是似乎仍然过度使用继承。当A
继承B
时,这是一种说B
是A
的方式。这里肯定不是这样。私人继承"黑客"使这种尴尬变得无形,这就是为什么它对我来说似乎是可以接受的。
为什么不专门研究相同基类的情况呢?如果可以的话,我使用了boost的mpl::if_而不是我的和c ++ 11或boost的type_trait的is_same。我手边没有编译器,所以下面可能存在一些语法问题
#include <type_traits>
template<typename S, typename T>
class roundtrip_diff : private S, private T {
public:
void printSchedule(void) {
std::cout<<"away: ";
S::move();
std::cout<<"return: ";
T::move();
}
};
template<typename S>
class roundtrip_same : private S {
public:
void printSchedule(void) {
std::cout<<"away: ";
S::move();
std::cout<<"return: ";
S::move();
}
};
template<bool, typename True, typename False> struct if_{ typedef True type; };
template<typename True, typename False> struct if_<false,True,False> { typedef False type; };
template<typename A, typename B> struct is_same { enum{value=0}; };
template<typename A> struct is_same<A,A> { enum{value=1}; };
template<typename S, typename T>
class roundtrip : if_< is_same<S,T>::value, roundtrip_same<S>, roundtrip_diff<S,T> >::type { };
显然,当您允许任意数量的参数时,需要找到更优雅的解决方案,但我认为这应该消除重复基础的错误。
- C++17中的并行执行策略
- 运行时执行策略不同
- 编译器上的策略数据结构不起作用
- 我应该在简单的策略游戏中为各个派系使用类吗 - C++
- 给定一个C++嵌套的私有结构类型,是否有从文件范围静态函数访问它的策略
- 没有执行策略的 std::transform_reduce 是可移植的吗?
- C++ 运算符修改/元编程策略,用于不那么冗长的语法
- 使用 Qt5 SQL 进行异步数据库访问的策略
- C++基于策略的设计:继承与组合
- 当PSO细粒度策略对使用AdsGetObject MSDN API的Windows操作系统生效时,如何获取用户密码到期日
- 如何在源代码中使用执行策略检测 C++17 的扩展内存管理算法的可用性?
- 如何实例化基于输入的策略模式
- 使用策略模式设计软件时出现的问题
- 在发送源代码时省略未使用的boost src文件的策略
- 使用 redis 进行日志缓存:是否可以创建逐出到 PostgreSQL 的逐出策略?
- CMAKE:前导或尾随空格(策略CMP0004)
- 转换非常长的字符串文本C++以满足最大行长策略
- 在插入顺序已知时填充 Eigen3 稀疏矩阵的策略
- C++ 中的执行策略
- 如何获取应用于本地工作站的组策略对象列表