C++中向上转型变量为何调用派生类虚函数?附相关问题
C++多态与类型转换问题解答
提供的代码
类定义
class Person { public: Person(const std::string& name, std::size_t age); virtual void print() const; void inc_age() { ++_age; } private: std::string _name; std::size_t _age; }; class Employee : public Person { public: Employee(const std::string& name, std::size_t age, double salary); virtual void print() const override; void add_bonus(double percent); private: double _salary; };
main函数
int main() { Person mike{"Mike"s, 20}; Employee manager{"Sam"s, 35, 100}; Person* p{&manager}; if (p) p->print(); // this line std::cout << '\n'; return 0; }
问题
- 原本认为向上转型后应调用
Person::print(),但实际却调用了Employee::print(),即使使用static_cast<Person*>(p)->print()也是如此。想了解:如何在不发生切片(切片是否属于未定义行为?)的情况下调用Person::print()? - 教授提到:若类不是多态类(无虚函数),使用
dynamic_cast不会报错,会静默产生未定义行为。该说法是否正确?有什么方法可以避免这种情况?
解答
问题1:调用基类print()且避免切片
- 显式类名限定调用:直接通过基类名限定函数调用,就能绕过虚函数的动态绑定机制,强制调用基类版本的
print()。写法如下:
这种操作不会触发切片——切片是指将派生类对象赋值给基类对象时,派生类独有成员被截断的行为,这里仅调用基类成员函数,没有对象赋值操作,完全不存在切片问题。p->Person::print(); - 切片的性质:切片本身是标准定义的合法行为,不属于未定义行为。当把
Employee对象赋值给Person对象时,只会保留基类部分的成员,派生类的_salary会被丢弃,这是C++标准明确规定的行为。
问题2:非多态类使用dynamic_cast的行为
- 教授的说法是正确的。根据C++标准,
dynamic_cast仅允许用于多态类型(即包含至少一个虚函数的类)。若对非多态类使用dynamic_cast,属于未定义行为——程序可能崩溃、输出异常结果,或看似正常运行但行为不可预测,且编译器不强制报错(部分编译器会给出警告,但并非必须)。 - 避免方法:
- 限定
dynamic_cast的使用场景:仅对多态类使用该转换,通常建议将基类的析构函数设为虚函数,这既是多态类的必要条件,也是避免内存泄漏的良好编程习惯。 - 替代方案:若类无需多态但必须转换,优先使用
static_cast(需确保你明确知晓指针/引用的实际类型,保证转换安全);或重新设计类结构,将其改为多态类以支持dynamic_cast的安全使用。
- 限定
内容的提问来源于stack exchange,提问作者ProMike
相关产品推荐
相关产品推荐

