C 等效于将 <T extends Class> 用于 java 参数/返回类型

新手上路,请多包涵

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

 public <T extends MyClass> T foo(T bar) {...}

有与此等效的 C++ 吗?

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

原文由 ricky3350 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 619
2 个回答

如果您有可用的 C++11 或更高版本,我们可以在这里使用 enable_if

 template<typename T, typename std::enable_if<std::is_base_of<MyClass, T>::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<typename T, typename std::enable_if<std::is_base_of<MyClass, T>::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;
}

现场演示

原文由 AndyG 发布,翻译遵循 CC BY-SA 3.0 许可协议

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

template <typename T> T foo(T bar) {...}

无需指定界限。

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

编译器必须对方法体中 T 类型的使用进行类型检查,例如方法调用、字段访问等,但不知道 T 是什么,因此您必须提供一个界限,因此编译器可以满足例如一个方法调用是有效的,因为它是在满足该界限的所有类型上定义的。例如,如果您在方法的主体中有表达式 bar.baz() ,则编译器只会让您编译如果类型 MyClass (以及它的所有子类型)提供该方法 .baz() ;如果您没有提供任何界限,编译器会抱怨 Object (隐式上限)没有方法 .baz()

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

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

原文由 newacct 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题