实现';有界泛型';在C++; 我把一个项目从java转移到C++,在java中有一些比较简单的问题。
我有一个类实现';有界泛型';在C++; 我把一个项目从java转移到C++,在java中有一些比较简单的问题。,c++,templates,generics,C++,Templates,Generics,我有一个类X,用于处理Y类型的对象和从Y继承的对象X通常需要从Y调用一个方法,比如说kewl\u method(),这个方法在继承自Y的每个类中都是不同的。在Java中,我可以这样做: public class X<y extends Y> 公共类X 我会在X中调用kewl\u method(),而不会感到头痛,它会做我想做的事情。如果我理解正确(我是C++新手),C++中没有这样的有界泛型,所以如果我使用一个模板,它有“代码> x ,那么它就可以完全填充任何东西,而我不能调用
X
,用于处理Y
类型的对象和从Y
继承的对象X
通常需要从Y
调用一个方法,比如说kewl\u method()
,这个方法在继承自Y
的每个类中都是不同的。在Java中,我可以这样做:
public class X<y extends Y>
公共类X
我会在X
中调用kewl\u method()
,而不会感到头痛,它会做我想做的事情。如果我理解正确(我是C++新手),C++中没有这样的有界泛型,所以如果我使用一个模板,它有“代码> x <代码>,那么它就可以完全填充任何东西,而我不能调用<代码> KeWLL方法()/<代码>的变体。
在C++中,最好的方法是什么?使用石膏
限制:我不能使用boost或TR1。如果我理解正确,将
Y::kewl\u方法
虚拟化将是一个很好的Java翻译。您不希望在派生自Y
的类中重载它,只需按如下方式键入它:
template<class T>
void method()
{
T t;
t.kewl_method();
}
模板
void方法()
{
T;
t、 kewl_方法();
}
如果您以错误的方式使用它,编译器将给您一个错误,即kewl_method()不是[type of T]的成员 您在Java中所指的构造是泛型。在C++中最接近的对应的东西是模板。 因此,C++中所呈现的最接近的翻译将是
template<class T>
class X
{
// Here you use T as Y or type derived from it
// for example
void method(T& y)
{
y.kewl_method();
}
};
你也可以使用
X<Z> b;
xb;
这是可以接受的。在C++中,模板是鸭式的,即您可以调用任何类型的<代码> t>代码>,只要实际指定的类型有此方法,它就正确了。 我理解,您要强制传递给您的类模板的模板参数是从某个<代码>类y继承的。我应该注意到,您不能使用boost是非常不幸的。我将提供一个带有boost的解决方案
template <class T, bool OK> class XImpl; //no definition, just declaration
template <class T> class XImpl<T, true> //partial specialization
{
//here goes your real class definition
};
template <class T> class X : public XImpl<T, boost::is_base_and_derived<Y, T>::value >
{}; //if T isn't derived from Y, compilation will fail because you are trying to
//inherit from an incomplete (undefined) type
模板类XImpl//没有定义,只有声明
模板类XImpl//部分专门化
{
//这是您真正的类定义
};
模板类X:公共XImpl
{}; //如果T不是从Y派生的,编译将失败,因为您正在尝试
//从不完整(未定义)类型继承
我们使用的唯一
boost
部分是基于和派生的元函数。您可以查看boost源代码,了解它是如何实现的,然后自己实现它。HTH使用模板,但对其工作的类型进行限制:
template<typename T>
void
X::some_member(T& t)
{
// Triggers a compile-time error if/when T is not derived from Y
STATIC_ASSERT(( is_base_of<Y, T> ));
t.kewl_method();
}
模板
无效的
X::一些_成员(T&T)
{
//如果T不是从Y派生的,则触发编译时错误
静态断言((是的基);
t、 kewl_方法();
}
因为您没有使用Boost,所以必须实现静态断言
,并且是
的基础。第一个有点简单,但第二个不是这样(尽管你可以使用一个可转换的特征作为近似值)。(was:heishe),就我而言
但我想谈谈你的问题:
所以,如果我使用一个带有X的模板,就可以用任何东西来填充它
不,因为如果没有可访问的kewl\u方法
,它将无法编译
您必须记住,在Java中,有界泛型并不像您认为的那样限制泛型类所接受的类型,更多的是为泛型类提供关于其泛型类型T的更完整信息,以便能够在编译时验证对其方法的调用
在C++中,这个特性是按编译器的使用方式提供的:以类似于鸭类型的方式,但在编译时解决,编译器将只在泛型类型类访问“代码> KeWLIHead < /COD> > < /P>时接受该方法的编译。
关于4个类的示例:
class X
{
public : virtual void kewl_method() { /* etc. */ }
} ;
class Y : public X
{
public : virtual void kewl_method() { /* etc. */ }
} ;
class Z
{
public : virtual void kewl_method() { /* etc. */ }
} ;
class K
{
public : virtual void wazaa() { /* etc. */ }
} ;
正规C++解决方案
使用C++模板,可以为模板类提供A:
template<typename T>
class A
{
public :
void foo()
{
T t ;
t.kewl_method() ;
}
} ;
您需要调用foo()
方法来阻止编译
如果真的需要约束怎么办?
如果要显式地将其限制为从X继承的类,则必须自己使用代码(直到标准化这些类…它们错过了C++0x截止日期,所以我想我们必须等待下一个标准…)
如果您真的想设置约束,有多种方法。虽然我知道这一点,但我对这个概念还不够熟悉,无法为您提供解决方案,但我仍然可以看到两种方法来为您的案例应用约束(虽然它们是针对g++4.4.5进行测试的,但是否有更明智的人可以验证我的代码?)
添加未使用的强制转换?
B类与A类相似,但有一行代码:
template<typename T> // We want T to derive from X
class B
{
public :
void foo()
{
// creates an unused variable, initializing it with a
// cast into the base class X. If T doesn't derive from
// X, the cast will fail at compile time.
// In release mode, it will probably be optimized away
const X * x = static_cast<const T *>(NULL) ;
T t ;
t.kewl_method() ;
}
} ;
但是,作为示例,您需要调用foo()
方法来阻止编译
在类中添加自制的“约束”?
让我们创建一个类来表示其构造函数上的约束:
template<typename T, typename T_Base>
class inheritance_constraint
{
public:
inheritance_constraint()
{
const T_Base * t = static_cast<const T *>(NULL) ;
}
} ;
模板
类继承约束
{
公众:
继承约束()
{
const T_Base*T=静态_转换(NULL);
}
} ;
你会注意到这个类是空的,它的构造函数什么都不做,所以很有可能它会被优化掉
您可以在以下示例中使用它:
template<typename T>
class C : inheritance_constraint<T, X> // we want T to derive from X
{
public :
void foo()
{
T t ;
t.kewl_method() ;
}
} ;
模板
类C:继承\约束//我们希望T从X派生
{
公众:
void foo()
{
T;
t、 kewl_方法();
}
} ;
私有继承意味着您的“继承_约束”不会影响您的代码,但它仍然在编译时表示一个约束,该约束将停止对不是从X派生的类T的编译:
结果将是:
int main()
{
// A's constraint is : implements kewl_method
A<X> x ; x.foo() ; // OK: x implements kewl_method
A<Y> y ; y.foo() ; // OK: y derives from X
A<Z> z ; z.foo() ; // OK: z implements kewl_method
A<K> k ; k.foo() ; // NOT OK : K won't compile: /main.cpp error:
// ‘class K’ has no member named ‘kewl_method’
return 0;
}
int main()
{
// B's constraint is : implements kewl_method, and derives from X
B<X> x ; x.foo() ; // OK : x is of type X
B<Y> y ; y.foo() ; // OK : y derives from X
B<Z> z ; z.foo() ; // NOT OK : z won't compile: main.cpp| error:
// cannot convert ‘const Z*’ to ‘const X*’
// in initialization
B<K> k ; k.foo() ; // NOT OK : K won't compile: /main.cpp error:
// cannot convert ‘const K*’ to ‘const X*’
// in initialization
return 0 ;
}
int main()
{
// C's constraint is : implements kewl_method, and derives from X
C<X> x ; // OK : x is of type X
C<Y> y ; // OK : y derives from X
C<Z> z ; // NOT OK : z won't compile: main.cpp error:
// cannot convert ‘const Z*’ to ‘const X*’
// in initialization
C<K> k ; // NOT OK : K won't compile: /main.cpp error:
// cannot convert ‘const K*’ to ‘const X*’
// in initialization
return 0 ;
}
intmain()
{
//C的约束是:实现kewl_方法,并且
template<typename T>
class C : inheritance_constraint<T, X> // we want T to derive from X
{
public :
void foo()
{
T t ;
t.kewl_method() ;
}
} ;
int main()
{
// C's constraint is : implements kewl_method, and derives from X
C<X> x ; // OK : x is of type X
C<Y> y ; // OK : y derives from X
C<Z> z ; // NOT OK : z won't compile: main.cpp error:
// cannot convert ‘const Z*’ to ‘const X*’
// in initialization
C<K> k ; // NOT OK : K won't compile: /main.cpp error:
// cannot convert ‘const K*’ to ‘const X*’
// in initialization
return 0 ;
}
template<typename T, typename T_Base>
void apply_inheritance_constraint()
{
// This code does nothing, and has no side effects. It will probably
// be optimized away at compile time.
const T_Base * t = static_cast<const T *>(NULL) ;
} ;
template<typename T>
class D
{
public :
void foo()
{
// Here, we'll verify if T inherits from X
apply_inheritance_constraint<T, X>() ;
T t ;
t.kewl_method() ;
}
} ;
int main()
{
// D's constraint is : implements kewl_method, and derives from X
D<X> x ; // OK : x is of type X
D<Y> y ; // OK : y derives from X
D<Z> z ; // NOT OK : z won't compile: main.cpp error:
// cannot convert ‘const Z*’ to ‘const X*’
// in initialization
D<K> k ; // NOT OK : K won't compile: /main.cpp 2 errors:
// ‘class K’ has no member named ‘kewl_method’
// cannot convert ‘const K*’ to ‘const X*’
// in initialization
return 0 ;
}