添加字符串类型的类成员会导致调用基类函数而不是子函数
Adding a string-type class member causes base class function to be called instead of child
为什么下面的代码打印0,但如果你注释掉"std::string my_string",它会打印1?
#include <stdio.h>
#include <iostream>
class A {
public:
virtual int foo() {
return 0;
}
private:
std::string my_string;
};
class B : public A {
public:
int foo() {
return 1;
}
};
int main()
{
A* a;
if (true) {
B b;
a = &b;
}
std::cout << a->foo() << std::endl;
return 0;
}
我也明白将 std::string 更改为 std:string* 也会导致代码打印 1,删除 if 语句也是如此,尽管我不明白为什么这是真的。
编辑:这似乎是由于悬空的指针。那么C++在 Java 中做这样的事情的标准模式是什么:
Animal animal;
boolean isDog = false;
// get user input to set isDog
if (isDog) {
animal = new Dog();
} else {
animal = new Cat();
}
animal.makeNoise(); // Should make a Dog/Cat noise depending on value of isDog.
问题
该程序具有未定义的行为。b
仅在if
体内的范围内。在访问悬空指针时,您不能指望逻辑结果。
int main()
{
A* a;
if (true) {
B b; // b is scoped by the body of the if.
a = &b;
} // b's dead, Jim.
std::cout << a->foo() << std::endl; // a points to the dead b, an invalid object
return 0;
}
TL;容灾解决方案
int main()
{
std::unique_ptr<A> a; // All hail the smart pointer overlords!
if (true) {
a = std::make_unique<B>();
}
std::cout << a->foo() << std::endl;
return 0;
} // a is destroyed here and takes the B with it.
解释
您可以将a
指向具有动态生存期的对象
int main()
{
A* a;
if (true) {
a = new B; // dynamic allocation
} // b's dead, Jim.
std::cout << a->foo() << std::endl;
delete a; // DaANGER! DANGER!
return 0;
}
不幸的是,delete a;
也是未定义的行为A
因为它具有非virtual
析构函数。如果没有虚拟析构函数,a
指向的对象将作为A
被销毁,而不是作为B
。
解决方法是A
提供一个虚拟析构函数,以允许它销毁正确的实例。
class A {
public:
virtual ~A() = default;
virtual int foo() {
return 0;
}
private:
std::string my_string;
};
没有必要修改B
因为一旦一个函数被声明为virtual
,它就会保持virtual
它的子函数。请留意final
。
但最好避免原始动态分配,因此我们可以再进行一项改进:使用智能指针。
这让我们回到解决方案。
std::unique_ptr
文档
std::make_unique
文档
相关文章:
- 使用子类覆盖基类中定义的函数
- 如何基于模板化类的基类专门化成员函数
- C++虚拟函数:基类函数是调用的,而不是派生的
- 复制派生类更改基类的构造函数
- memcpy派生类到基类,为什么还调用基类函数
- 无法在 c++ 中使用参数从 dericed 类调用基类构造函数
- 为具有不同签名的函数的派生类设计基类
- 我们是否应该从派生类调用基类移动复制/分配构造函数
- C++使用派生类调用基类成员函数的继承
- 使用多个派生类调用基类成员函数
- 派生模板类中基类构造函数的可见性
- 从派生类实现基类构造函数专用化的替代方法是什么
- 从派生类调用基类函数时出现问题
- 仅授予派生类对基类数据成员/函数的 const 访问权限
- 虚拟函数-基类指针
- 当基类未指定构造函数时,如何使用仅具有带参数的构造函数的类派生基类?
- 从派生类访问基类函数
- 我不希望派生类继承基类的构造函数
- 成员函数指针强制转换,从派生类到基类
- 如何访问受保护的基类函数,从派生类通过基类ptr