添加字符串类型的类成员会导致调用基类函数而不是子类

Hyd*_*dra 3 c++ polymorphism inheritance

为什么下面的代码显示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;
}
Run Code Online (Sandbox Code Playgroud)

我也理解将std :: string更改为std:string *也会导致代码打印1,就像删除if语句一样,尽管我不明白为什么其中任何一个都是正确的。

快点

编辑:这似乎是由于悬空的指针。那么,在Java中执行此类操作的C ++标准模式是什么:

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.
Run Code Online (Sandbox Code Playgroud)

use*_*301 5

问题

该程序具有未定义的行为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;
}
Run Code Online (Sandbox Code Playgroud)

TL; DR解决方案

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. 
Run Code Online (Sandbox Code Playgroud)

说明

您可以指向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;
}
Run Code Online (Sandbox Code Playgroud)

不幸的delete a;是,由于A具有非virtual析构函数,因此也是未定义的行为。如果没有虚拟析构函数,则所指向的对象a将被破坏为A,而不是B

解决方法是提供A一个虚拟析构函数,使其能够销毁正确的实例。

class A {
  public:
    virtual ~A() = default;
    virtual int foo() {
      return 0;
    }
  private:
    std::string my_string;
};
Run Code Online (Sandbox Code Playgroud)

无需修改,B因为一旦声明了函数virtual,该函数将virtual为其子代保留。密切注意final

但是最好避免原始的动态分配,因此我们可以做更多的改进:使用智能指针

这使我们回到了解决方案。

有关的文件 std::unique_ptr

有关的文件 std::make_unique