在 C++ 中具有继承的对象向量
Posted
技术标签:
【中文标题】在 C++ 中具有继承的对象向量【英文标题】:vector of objects with inheritance in C++ 【发布时间】:2011-02-17 11:52:20 【问题描述】:class IFeature
public:
virtual std::string string() = 0;
;
class Feature2D
public:
virtual std::string string() ....
;
class Feature3D
public:
virtual std::string string() ....
;
void print(std::vector<IFeature*> & v)
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
void main()
std::vector<Feature2D*> v2d;
// push...
print(v2d); // compile error
std::vector<Feature3D*> v3d;
// push...
print(v3d); // compile error
关于如何获得此打印功能的任何建议? (可能使用与 std::vector 不同的另一个数据结构)
谢谢
【问题讨论】:
您可以(并且应该)通过 const 引用将您的向量传递给print
。此外,FeatureXD
类声明中缺少继承语句。
@Stefan - 请不要建议对问题中发布的代码进行编辑。很可能任何错误都是 OP 看到的问题的原因。
是的,当然,我在想什么 :)
【参考方案1】:
使用模板。
template<typename T> void print(std::vector<T *> const & v)
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
或者,使用虚拟打印成员函数:
class IFeature
public:
virtual std::string string() = 0;
virtual void print(std::ostream & Dest) const = 0;
;
void print(std::vector<IFeature *> const & v)
for (size_t i=0; i<v.size(); i++)
v[i]->print(cout);
cout << endl;
可选地与操作符组合
inline std::ostream & operator<<(std::ostream & Dest, IFeature const & v)
v.print(Dest);
return Dest;
void print(std::vector<IFeature *> const & v)
for (size_t i=0; i<v.size(); i++)
std::cout << *(v[i]) << std::endl;
【讨论】:
非常感谢!那个“const”是干什么用的? 表示打印不会修改v。【参考方案2】:只需制作向量 IFeature* -向量。您可以在其中存储继承类的指针。
std::vector<IFeature*> v2d;
v2d.push_back(new Feature2D());
print(v2d);
无需使用模板。当您需要访问常见的虚函数时,可以使用指向超类的指针。这样你也可以在同一个向量中混合不同的子类:
std::vector<IFeature*> vMixed;
vMixed.push_back(new Feature2D());
vMixed.push_back(new Feature3D());
print(vMixed);
当然,如果您还需要继承类的指针,事情就会变得有点棘手。一种选择是将它们单独存储在其他地方。你也可以低调,但这通常是不推荐的。
【讨论】:
但是,如果您需要通过向量访问继承的类,这将不起作用。 (你需要丑陋的沮丧。)【参考方案3】:为了完整起见,我将补充一点,您可以重新解释转换向量,因为所有向量共享相同的二进制代码。
print(reinterpret_cast<std::vector<IFeature*>&>(v2d));
C++ 没有模板参数的协方差,但如果你知道它在底层做了什么,你可以部分模拟它。我发现 reinterpret_cast 对于将 vector<T*>&
转换为 vector<const T*>&
以实现逆变也很有用。
当然,这很丑。
【讨论】:
【参考方案4】:您可以将print
本身制作成模板:
template<typename T>
void print(T const &v)
for (size_t i=0; i<v.size(); i++)
std::cout << v[i]->string() << std::endl;
更好的是,使用迭代器,然后它也可以在大多数其他标准容器上工作:
template<typename T>
void print(T const &v)
for (T::const_iterator i = v.begin(); i != v.end(); ++i)
std::cout << (*i)->string() << std::endl;
更好(感谢 Pedro),自己传递迭代器:
template<typename Iter>
void print(Iter begin, Iter end)
for (Iter i = begin; i != end; ++i)
std::cout << (*i)->string() << std::endl;
【讨论】:
我会更进一步,建议您对迭代器进行操作,而不是对 T 的 const 引用进行操作。所以:template您在这里寻找的是接口协方差,这(据我所知)在 C++ 类上是不可能的。您还需要将 print 设为模板函数(将 IFeature* 替换为 T*)。
【讨论】:
以上是关于在 C++ 中具有继承的对象向量的主要内容,如果未能解决你的问题,请参考以下文章