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

九头蛇

为什么下面的代码显示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语句一样,尽管我不明白为什么其中任何一个都是正确的。

快点

编辑:这似乎是由于悬空的指针。那么,在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.
用户名

问题

该程序具有未定义的行为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; 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. 

说明

您可以指向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

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如果使用Flash Builder 4.7(而不是4.6),则基类中的静态函数不想在子类上调用成员函数

来自分类Dev

为什么C ++ 11字符串新函数(stod,stof)不是字符串类的成员函数?

来自分类Dev

为什么C ++ 11字符串新函数(stod,stof)不是字符串类的成员函数?

来自分类Dev

基类中基类子类型的成员变量

来自分类Dev

属性从基类返回字符串,而成员从继承的类返回字符串?

来自分类Dev

从父类到子类函数的文档字符串

来自分类Dev

函数调用父类方法而不是子类?

来自分类Dev

字符串类成员的移动构造函数的行为

来自分类Dev

静态向量对字符串类成员函数

来自分类Dev

将字符串数组存储在类成员函数中并返回

来自分类Dev

将字符串数组存储在类成员函数中并返回

来自分类Dev

C ++当我不知道子类型时,从基类中调用子类函数

来自分类Dev

C ++当我不知道子类型时,从基类中调用子类函数

来自分类Dev

无法将字符串数组声明为类成员

来自分类Dev

无法将字符串数组声明为类成员

来自分类Dev

将字符串流提供给类成员函数

来自分类Dev

调用基类构造函数与初始化子类中的成员变量

来自分类Dev

类类型未知时调用成员函数

来自分类Dev

从基类构造函数调用派生类的成员函数

来自分类Dev

从使用派生类成员函数的基类调用函数

来自分类Dev

错误:“函数”不是非静态数据成员或“类”的基类

来自分类Dev

在 Python 中,如何将类/函数的调用转换为字符串?

来自分类Dev

从字符串创建类实例并调用构造函数

来自分类Dev

使用字符串调用类函数

来自分类Dev

与子类一起调用时,重载的函数模板匹配模板而不是基类

来自分类Dev

为什么类中的ostringstream类型的成员导致“调用隐式删除的复制构造函数”错误?

来自分类Dev

C ++模板:从基类调用派生模板类的成员函数

来自分类Dev

EmberJs将函数的返回字符串添加为类名

来自分类Dev

根据字符串访问类成员

Related 相关文章

  1. 1

    如果使用Flash Builder 4.7(而不是4.6),则基类中的静态函数不想在子类上调用成员函数

  2. 2

    为什么C ++ 11字符串新函数(stod,stof)不是字符串类的成员函数?

  3. 3

    为什么C ++ 11字符串新函数(stod,stof)不是字符串类的成员函数?

  4. 4

    基类中基类子类型的成员变量

  5. 5

    属性从基类返回字符串,而成员从继承的类返回字符串?

  6. 6

    从父类到子类函数的文档字符串

  7. 7

    函数调用父类方法而不是子类?

  8. 8

    字符串类成员的移动构造函数的行为

  9. 9

    静态向量对字符串类成员函数

  10. 10

    将字符串数组存储在类成员函数中并返回

  11. 11

    将字符串数组存储在类成员函数中并返回

  12. 12

    C ++当我不知道子类型时,从基类中调用子类函数

  13. 13

    C ++当我不知道子类型时,从基类中调用子类函数

  14. 14

    无法将字符串数组声明为类成员

  15. 15

    无法将字符串数组声明为类成员

  16. 16

    将字符串流提供给类成员函数

  17. 17

    调用基类构造函数与初始化子类中的成员变量

  18. 18

    类类型未知时调用成员函数

  19. 19

    从基类构造函数调用派生类的成员函数

  20. 20

    从使用派生类成员函数的基类调用函数

  21. 21

    错误:“函数”不是非静态数据成员或“类”的基类

  22. 22

    在 Python 中,如何将类/函数的调用转换为字符串?

  23. 23

    从字符串创建类实例并调用构造函数

  24. 24

    使用字符串调用类函数

  25. 25

    与子类一起调用时,重载的函数模板匹配模板而不是基类

  26. 26

    为什么类中的ostringstream类型的成员导致“调用隐式删除的复制构造函数”错误?

  27. 27

    C ++模板:从基类调用派生模板类的成员函数

  28. 28

    EmberJs将函数的返回字符串添加为类名

  29. 29

    根据字符串访问类成员

热门标签

归档