在运算符中动态强制转换为派生类型<<
Dynamic cast to derived type in operator<<
我有一个基类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;
}
我想包括一个具有成员std::vector<Tag*>
的第三类TagList
,它可以容纳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<<
函数中的常量有关?欢迎就如何实现这一目标提出其他建议。
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())
{}
如果我可以建议一个不同的解决方案来解决输出Tag
对象的问题,那么只有一个运算符重载,对于Tag const&
,然后在Tag
结构中调用虚拟output
函数。然后在继承的类中重写该函数。
也许像
struct Tag
{
...
virtual std::ostream& output(std::ostream& out)
{
return out << "This is Tagn";
}
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 TagSetn";
}
};
然后输出列表
for (auto t : ts.tags)
std::cout << *t;
你不能这样做,因为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;
}
现在,您也可以在TagList
中使用方法print()
,而无需任何强制转换:
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 << ", ";
}
您当前的方法本质上是手写的 RTTI,具有额外的内存开销。使用动态强制转换将其与内置 RTTI 混合将不起作用,因为类 Tag
和 TagSet
不是多态的,并且这些类型的对象的内置 RTTI 在运行时不可用来执行此类转换。如果您坚持使用手写RTTI,则需要执行static_cast
。
TagSet & tset{static_cast<TagSet &>(*t)};
相关文章:
- 为什么使用 "this" 指针调用派生成员函数?
- 具有奇怪重复模板模式的派生类中的成员变量已损坏
- 在派生函数中指定void*参数
- 如何通过派生类函数更改基类中的向量
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 如何委托派生类使用其父构造函数?
- 呼叫运营商<<临时
- 如何使用单独文件中的派生类访问友元函数对象
- 派生类销毁的最佳实践是什么
- 如何使用基类指针引用派生类成员
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 使用基类指针创建对象时,缺少派生类析构函数
- 如何引用基类的派生类?
- 存储模板类型以强制转换回派生<T>
- 需要从 istream 和 ostream 派生 iostream
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 在 C++ 中用派生类型重写成员函数
- 具有多个类、派生类的C++正向声明
- <<操作员在下面的行中工作
- 有没有一种"cleaner"的方法可以在指向基的指针向量中找到派生类的第一个实例?