我有一个类模板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();
}
};
答案 0 :(得分:2)
您可以将数据成员添加到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>
)
答案 1 :(得分:1)
如noticed by 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;
};
中使用它们。
A
更新(响应OP的编辑):
您的解决方案一般情况良好,但仍然似乎过度使用继承。当B
继承B
时,可以说A
的是 {{1}}。肯定不是这样的。私人继承“黑客”使这种尴尬看不见,这就是为什么它似乎为我所接受。
答案 2 :(得分:0)
为什么不专注于相同基类的情况? 如果可以的话,我使用了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 { };
显然,当你允许任意数量的参数时,需要找到一个更优雅的解决方案,但我认为这应该可以消除重复基数的错误。