向vector对象添加模板类的实例(c++)



在下面的代码中,当我试图将fooBaz推到v时,我得到一个编译器错误。这让我很惊讶,因为BazBar的派生类。

为什么这是不允许的,我能做些什么,如果我想把几个Foo实例,模板化的类派生自相同的基类,成一个矢量?

#include <iostream>
#include <vector>
template<typename T>
class Foo {};
struct Bar {};
struct Baz : public Bar {};
int main() {

Foo<Bar> fooBar;
Foo<Baz> fooBaz;

std::vector<Foo<Bar>> v;
v.push_back(fooBar);
v.push_back(fooBaz);
return 0;
}

Java泛型与c++模板不同。

c++的类类型值与Java的类类型引用变量是不同的。

这两个问题你都碰到了。

c++模板为每组模板参数生成一个新的、不相关的类型。你可以创建一个公共基础,但你必须自己做。

Java泛型实际上创建了一个类。然后在输入和输出处写强制转换操作。

所以Java泛型,Foo<Base>Foo<Derived>是相关的,因为Java泛型实际上创建了Foo<Object>,然后将其包装在强制转换中,并且Foo<Base>Foo<Derived>中的强制转换是兼容的。(好吧,不总是Object,你用信息标记泛型参数,Java使用这些信息来确定它写泛型的实际类型,但这给了你一个想法)。

在c++中,没有关系。(模板模式匹配提供了编译时关系,但根本没有运行时关系)

第二个问题是,您将类类型的值视为引用。在c++中,Foo是一个实际的foo。它表示一个内存块,该内存块是该类的一个实例。在Java中,Foo是一个智能指针,指向堆上某处遵循Foo协议的对象(是一个派生类)。

在Java中不能很容易地创建Foo类型的值,在c++中也不能很容易地创建标记并将智能指针扫描到Foo类型。

Foo<Bar> fooBar;
Foo<Baz> fooBaz;

这是两个不相关的类型。它们被存储在堆栈中(自动存储)。

std::vector<Foo<Bar>> v;

存储一个包含Foo<Bar>对象的内存缓冲区。

v.push_back(fooBar);

fooBar实例从自动存储复制到vector

v.push_back(fooBaz);

这不起作用,因为fooBarfooBaz是不相关的类型。

现在,在c++23反射之前,在c++中模仿Java的工作是很困难的。你必须手动执行一些步骤。

首先,当手动告诉Foo理解继承:

struct empty_t {};
template<class T, class Base=empty_t>
class Foo:Foo<Base> {};
template<>
class Foo<empty_t, empty_t> {
virtual ~Foo() {}
};
struct Bar {};
struct Baz : public Bar {};

auto fooBar = std::make_unique<Foo<Bar>>();
auto fooBaz = std::make_unique<Foo<Baz, Bar>>();
std::vector<std::unique_ptr<Foo<Bar>>> v;
v.push_back(std::move(fooBar));
v.push_back(std::move(fooBaz));

这个编译。

在c++23中,编译时反射可以让你自动检测Baz的基类,如果你愿意,可以让Foo<Baz>自动从Foo<Bases>...继承。

现在,继承只是c++中处理多态性的一种方法,但我认为今天已经足够了。

正如评论中提到的,模板就像食谱。在类模板成为模板之前,需要实例化类模板来获得类。不同的实例化之间没有隐含的关系(除了相同模板的实例化)。当您考虑以下示例时,可能会更清楚:

template<typename T> struct Foo {};
template <> struct Foo<int> { void bar(){} };
template <> struct Foo<double> { void moo(){} };
int main() {
Foo<int> x;
x.bar();
Foo<double> y;
y.moo();
}

Foo<int>Foo<double>是两个不相关的类型,方法完全不同。如果它们不是模板的实例化,而是"普通的";如果不能将FooA压入std::vector<FooB>中,那就不足为奇了。

std::vector<Foo<Bar>>只能保存Foo<Bar>类型的元素。vector不知道这个类型是实例化模板Foo的结果。即使是这样,你也不能把Foo<Bar>赋值给Foo<Baz>,除非你提供一个转换。


实际上你的误解还有更多需要被揭穿的地方。假设你有一个std::vector<Bar>那么你也不能Baz压入该向量。看这里为什么不:什么是对象切片?这里是如何做的:https://stackoverflow.com/a/16126649/4117728.

相关内容

  • 没有找到相关文章