对于java参数/返回类型,C ++相当于使用

在java中,要创建一个返回与参数类型相同的对象并扩展某个类的函数,我会输入:

public  T foo(T bar) {...} 

有没有C ++相当于此?

换句话说,我如何创建一个函数,它接受任何扩展某个类的类,并返回相同的类型? (这是为了抽象/纯虚拟类的目的)。

如果您可以使用C ++ 11或更高版本,我们可以在此处使用enable_if

 template::value>::type* = nullptr> T Foo(T bar) { return T(); } 

例如:

 class MyClass { public: int a = 1; }; class Derived : public MyClass { public: int b = 2; }; class NotDerived { public: int b = 3; }; template::value>::type* = nullptr> T Foo(T bar) { return T(); } int main() { Derived d; NotDerived nd; std::cout << Foo(d).b << std::endl;; // works //std::cout << (Foo(nd)).b << std::endl;; //compiler error return 0; } 

现场演示

从技术上讲,正如其他答案所示,有一些方法可以在编译时将其限制为某种类型的子类型。 但是,大多数时候,你只会这样做

 template  T foo(T bar) {...} 

无需指定边界。

在Java中,generics需要边界,因为generics类或方法是与它的任何使用分开编译的。 通用类或方法被编译一次,成为字节码中的单个版本,单个版本能够处理调用者在其声明中满足其声明范围的任何参数。

编译器必须在方法体中对类型T使用进行类型检查,如方法调用,字段访问等,而不知道T是什么,因此必须提供一个绑定,以便编译器可以满足,例如a方法调用有效,因为它是在满足该范围的所有类型上定义的。 例如,如果在方法体中有表达式bar.baz() ,那么编译器只允许编译MyClass类型(因此它的所有子类型)提供方法.baz() ; 如果你没有提供边界,编译器会抱怨Object (隐式上限)没有方法.baz()

C ++模板是不同的。 对于用于它的每个不同类型参数,模板化的类或函数被“实例化”(再次编译)。 因此,在为特定T编译函数体时,编译器知道T是什么,并且能够直接对该类型的使用进行类型检查。

所以,如果你在函数体中有表达式bar.baz() ,那bar.baz()问题了。 如果您使用此函数,其中T是扩展MyClass的类型,那么它将编译正常,因为这样的类型具有.baz() 。 如果将此函数与不具有.baz()的类型一起使用,则在使用它时将无法编译。 如果你不小心使用了一个类型,该类型没有扩展MyClass但是有一个.baz()其参数类型和返回类型与你使用它的方式相匹配,它也会编译; 但这不一定是坏事。 C ++模板通常不与类型层次结构一起使用,而是需要提供类型需要提供的内容。 因此,例如,排序算法不要求其容器和/或元素类型扩展某种类型,而是容器提供某些特征(例如随机访问下标操作符),并且元素类型提供某些特征(例如,一个小于运营商)。

由于我不能对接受的答案发表评论,因此我提供了一个基于它的新答案。

通过使enable_if条件成为默认类型模板参数而不是nullptr可以简化模板参数 。

 template::value>>