多态性和引用 class 成员 - 调用了错误的虚拟方法
Polymorphism and reference class member - wrong virtual method called
我试图通过创建一个基础 class Document
来理解如何在 C++ 中应用多态性,从中可以得到两个 classes Book
和 Newspaper
是派生的。请注意如何在派生的 classes.
中覆盖虚方法 get_content()
class Document {
public:
virtual std::string get_content() const { return ""; }
};
class Book : public Document {
public:
std::string get_content() const override { return "Book"; }
};
class Newspaper: public Document {
public:
std::string get_content() const override { return "Newspaper"; }
};
Document
class 与Printer
class 聚合(引用),get_content()
适当派生的方法 class根据文档类型调用
class Printer {
public:
const Document& m_doc;
Printer(const Document& doc): m_doc(doc) {
std::cout << "Printing... " << m_doc.get_content() << std::endl;
}
std::string get_content() const { return m_doc.get_content(); }
};
到现在为止一切正常,但是一旦我将 Printer
class 与另一个 class Binding
聚合后,get_content()
似乎并没有再调用右派生的方法class
class Binding {
public:
Printer m_printer;
Binding(const Printer& printer): m_printer(printer) {
std::cout << "Binding... " << m_printer.get_content() << std::endl;
}
};
我不明白为什么下面这段代码...:[=31=]
int main() {
Printer p1(Book{});
Printer p2(Newspaper{});
Binding b1(p1);
Binding b2(p2);
}
...在第三行显示 Binding... Newspaper
而 Printing
显然正在获取一个 Book
实例作为输入:
Printing... Book
Printing... Newspaper
Binding... Newspaper
Binding... Newspaper
将 m_printer
声明为 Binding
class 中的引用也不能解决此问题。
据我了解,所讨论的示例应该可以正常工作,并提供类似
的输出
Printing... Book
Printing... Newspaper
Binding... Book
Binding... Newspaper
因为 lifetime extension of a temporary variable.
怀疑编译器中的错误是最后要做的事情,但是...使用的编译器是否正确实现了生命周期延长?
更新:生命周期延长规则不适用于 m_doc
class 成员,所以我的猜测是错误的。存在未定义的行为。
Printer p1(Book{});
Printer p2(Newspaper{});
在这里,您使用的是临时对象。这些对象在创建它们的语句结束时被销毁。
因此,您有悬空引用。在悬空引用上调用方法是未定义的行为。
在 C++ 中,您负责对象的生命周期。
(参考寿命延长不适用于此处)
我试图通过创建一个基础 class Document
来理解如何在 C++ 中应用多态性,从中可以得到两个 classes Book
和 Newspaper
是派生的。请注意如何在派生的 classes.
get_content()
class Document {
public:
virtual std::string get_content() const { return ""; }
};
class Book : public Document {
public:
std::string get_content() const override { return "Book"; }
};
class Newspaper: public Document {
public:
std::string get_content() const override { return "Newspaper"; }
};
Document
class 与Printer
class 聚合(引用),get_content()
适当派生的方法 class根据文档类型调用
class Printer {
public:
const Document& m_doc;
Printer(const Document& doc): m_doc(doc) {
std::cout << "Printing... " << m_doc.get_content() << std::endl;
}
std::string get_content() const { return m_doc.get_content(); }
};
到现在为止一切正常,但是一旦我将 Printer
class 与另一个 class Binding
聚合后,get_content()
似乎并没有再调用右派生的方法class
class Binding {
public:
Printer m_printer;
Binding(const Printer& printer): m_printer(printer) {
std::cout << "Binding... " << m_printer.get_content() << std::endl;
}
};
我不明白为什么下面这段代码...:[=31=]
int main() {
Printer p1(Book{});
Printer p2(Newspaper{});
Binding b1(p1);
Binding b2(p2);
}
...在第三行显示 Binding... Newspaper
而 Printing
显然正在获取一个 Book
实例作为输入:
Printing... Book
Printing... Newspaper
Binding... Newspaper
Binding... Newspaper
将 m_printer
声明为 Binding
class 中的引用也不能解决此问题。
据我了解,所讨论的示例应该可以正常工作,并提供类似
的输出Printing... Book
Printing... Newspaper
Binding... Book
Binding... Newspaper
因为 lifetime extension of a temporary variable.
怀疑编译器中的错误是最后要做的事情,但是...使用的编译器是否正确实现了生命周期延长?
更新:生命周期延长规则不适用于 m_doc
class 成员,所以我的猜测是错误的。存在未定义的行为。
Printer p1(Book{});
Printer p2(Newspaper{});
在这里,您使用的是临时对象。这些对象在创建它们的语句结束时被销毁。
因此,您有悬空引用。在悬空引用上调用方法是未定义的行为。
在 C++ 中,您负责对象的生命周期。
(参考寿命延长不适用于此处)