我有一个基类Tag
和一个子类TagSet
,它继承自Tag
。
class Tag
{
public:
Tag(std::string);
std::string tag;
};
std::ostream & operator <<(std::ostream &os, const Tag &t);
class TagSet : public Tag
{
public:
TagSet();
};
std::ostream & operator <<(std::ostream &os, const TagSet &ts);
及其实施
Tag::Tag(std::string t)
: tag(t)
{}
std::ostream & operator <<( std::ostream &os, const Tag &t )
{
os << "This is a tag";
return os;
}
TagSet::TagSet()
: Tag("SET")
{}
std::ostream & operator <<(std::ostream &os, const TagSet &ts)
{
os << "This is a TagSet";
return os;
}
我想要包含一个具有成员TagList
的第三个类std::vector<Tag*>
,该成员可以容纳Tag*
个实例或TagSet*
个实例。我想为<<
定义TagList
运算符,以便在元素为Tag
或operator<<
时使用Tag
版本的TagSet
如果元素是operator<<
,则TagSet
的版本。这是我的尝试:
std::ostream & operator <<(std::ostream &os, const TagList &ts)
{
for (auto t : ts.tags)
{
if (t->tag == "SET")
{
TagSet * tset = dynamic_cast<TagSet*>(t);
os << *tset << ", ";
}
else os << t->tag << ", ";
}
}
代码在运行时崩溃。我检查了tset
指针,它不是空的。可能它是一个糟糕的演员。
这样做的正确方法是什么?这个问题与operator<<
函数中的consts有关吗?关于如何实现这一点的其他建议是受欢迎的。
TagList
实现的其余部分是为了完整性:
class TagList
{
public:
TagList(std::vector<Tag*> taglist);
std::vector<Tag*> tags;
typedef std::vector<Tag*>::const_iterator const_iterator;
const_iterator begin() const { return tags.begin(); }
const_iterator end() const { return tags.end(); }
};
std::ostream & operator <<(std::ostream &os, const TagList &ts);
和
TagList::TagList(std::vector<Tag*> tagvec)
: tags(tagvec.begin(), tagvec.end())
{}
答案 0 :(得分:5)
如果我可以针对输出Tag
对象的问题提出不同的解决方案,那么Tag const&
只有一个运算符重载,然后将该调用设为虚拟output
Tag
结构中的函数。然后在继承的类中覆盖该函数。
也许像
struct Tag
{
...
virtual std::ostream& output(std::ostream& out)
{
return out << "This is Tag\n";
}
friend std::ostream& operator<<(std::ostream& out, Tag const& tag)
{
return tag.output(out);
}
};
struct TagSet : Tag
{
...
std::ostream& output(std::ostream& out) override
{
return out << "This is TagSet\n";
}
};
然后输出列表
for (auto t : ts.tags)
std::cout << *t;
答案 1 :(得分:1)
你不能这样做,因为operator<<
不是虚拟的。
定义虚拟print
方法,并在operator<<
中使用,例如
class Tag {
public:
virtual void print(std::ostream &f) const;
};
std::ostream & operator <<(std::ostream &os, const Tag &t)
{
t->print(os);
return os;
}
现在您可以在print()
中使用方法TagList
,而不需要任何演员:
std::ostream & operator <<(std::ostream &os, const TagList &ts)
{
for (auto t : ts.tags) {
t->print(os);
os << ", ";
}
}
或隐含
for (auto t : ts.tags) {
os << *t << ", ";
}
答案 2 :(得分:0)
您当前的方法本质上是一个手写的RTTI,具有额外的内存开销。由于类Tag
和TagSet
不是多态的,因此将它与内置RTTI混合使用动态转换不会有多态性,并且这些类型的对象的内置RTTI在运行时无法执行这样的演员。如果您坚持使用手写的RTTI,那么您需要执行static_cast
。
TagSet & tset{static_cast<TagSet &>(*t)};