ric*_*350 19 c++ java generics extends
在java中,要创建一个返回与参数类型相同的对象并扩展某个类的函数,我会输入:
public <T extends MyClass> T foo(T bar) {...}
Run Code Online (Sandbox Code Playgroud)
有没有C++相当于此?
换句话说,我如何创建一个函数,它接受任何扩展某个类的类,并返回相同的类型?(这是为了抽象/纯虚拟类的目的).
new*_*cct 19
从技术上讲,正如其他答案所示,有一些方法可以在编译时将其限制为某种类型的子类型.但是,大部分时间,你都会这样做
template <typename T> T foo(T bar) {...}
Run Code Online (Sandbox Code Playgroud)
无需指定边界.
在Java中,泛型需要边界,因为泛型类或方法是与它的任何使用分开编译的.通用类或方法被编译一次,成为字节码中的单个版本,单个版本能够处理调用者在其声明中满足其声明范围的任何参数.
编译器必须T在方法体中对类型的使用进行类型检查,如方法调用,字段访问等,而不知道是什么T,因此必须提供一个绑定,以便编译器可以满足,例如方法调用是有效的,因为它是在满足该范围的所有类型上定义的.例如,如果你bar.baz()在方法的主体中有表达式,编译器只会让你编译,如果类型MyClass(以及它的所有子类型)提供方法.baz(); 如果你没有提供边界,编译器会抱怨Object(隐式上限)没有方法.baz().
C++模板是不同的.对于用于它的每个不同类型参数,模板化的类或函数被"实例化"(再次编译).因此,在为特定代码T编译函数体时,编译器知道什么T是,并且能够直接对该类型的使用进行类型检查.
所以,如果你bar.baz()在函数体中有表达式,那就没问题了.如果你使用这个函数T作为扩展的类型MyClass,那么它将编译正常,因为这样的类型有一个.baz().如果您将此函数与没有a的类型一起使用.baz(),那么它将无法在使用它时进行编译.如果您意外地使用了一个类型不扩展MyClass但.baz()其参数类型和返回类型与您使用它的方式匹配的函数,它也会编译; 但这不一定是坏事.C++模板通常不与类型层次结构一起使用,而是与需要提供的类型有关.因此,例如,排序算法不要求其容器和/或元素类型扩展某种类型,而是容器提供某些特征(例如随机访问下标操作符),并且元素类型提供某些特征(例如,小于运营商).
And*_*dyG 14
enable_if如果你有C++ 11或更高版本,我们可以在这里使用
template<typename T, typename std::enable_if<std::is_base_of<MyClass, T>::value>::type* = nullptr>
T Foo(T bar)
{
return T();
}
Run Code Online (Sandbox Code Playgroud)
例如:
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;
}
Run Code Online (Sandbox Code Playgroud)
小智 7
由于我无法对已接受的答案发表评论,因此我在此基础上提供了一个新答案。
通过使enable_if条件成为默认类型的模板参数而不是,可以简化模板参数nullptr。
template<typename T, typename = std::enable_if<std::is_base_of<MyClass, T>::value>>
Run Code Online (Sandbox Code Playgroud)
也想知道同样的问题,这是通过概念的 C++20 方法。
#include <iostream>
#include <utility>
#include <concepts>
using namespace std;
class MyClass
{
public:
inline virtual void Print() const noexcept { cout << "Myclass" << endl; }
};
class Derived : public MyClass
{
public:
inline virtual void Print() const noexcept override { cout << "Derived" << endl; }
};
class NotDerived
{};
Run Code Online (Sandbox Code Playgroud)
创建一个名为 CheckType 的概念,当概念的参数 Type 是 BaseClass 或 DerivedClass : BaseClass 时,该概念得到满足。
template <class Type, class BaseClass>
concept CheckType = std::is_base_of<BaseClass, Type>::value;
Run Code Online (Sandbox Code Playgroud)
创建一个泛型类,其中 T 类型要求为 MyClass 或 Derived : MyClass 类型。
template <class T>
requires CheckType<T, MyClass>
class OnlyMyClass
{
private:
T Instance;
public:
inline void Print() const noexcept { Instance.Print(); } // Print
};
int main()
{
//OnlyMyClass<NotDerived> O1; // error, the associated constraints are not satisfied.
OnlyMyClass<MyClass> O2; // nice!
OnlyMyClass<Derived> O3; // nice!
O2.Print();
O3.Print();
return 0;
} // main
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11202 次 |
| 最近记录: |