【问题标题】:static pointer in C++ inheritanceC++ 继承中的静态指针
【发布时间】:2014-03-25 14:41:14
【问题描述】:

我很困惑为什么p->a() 打电话给B::a()?。 C++ 文档/标准中是否有段落很好地描述了这种行为?

#include <iostream>
using namespace std;

class A {
  public:
  A() { cout << "A ctor" << endl; a_instance = this; }
  static A *get_instance() { return a_instance; }
  static A *a_instance;
  void virtual a() { cout << "From base class" << endl; }
};

class B : public A {
public:
  B() { cout << "B ctor" << endl; b_instance = this; }
  static B *get_instance() { return b_instance; }
  static B *b_instance;
  void virtual a() { cout << "From derived class" << endl; }
};

A *A::a_instance = 0;
B *B::b_instance = 0;

main()
{
    cout << "Create A" << endl;
    A ab;
    cout << "Create B" << endl;
    B abc;
    B *ptr = B::get_instance();
    A *p = A::get_instance();

    cout << "Called from A object type" << endl;
    if (p) {
       p->a();
    }
}

【问题讨论】:

  • 各位...非常感谢!

标签: c++ pointers singleton polymorphism static-members


【解决方案1】:

当您创建变量abc 时,A 的构造函数将a_instance 设置为该实例。尽管p 是指向A 的指针,但由于实例指向B,因此它正确调用了B::a()

要解决此问题,您可以使用以下方法:

A* A::get_instance()
{
    static A a;
    return &a;
}

B* B::get_instance()
{
    static B b;
    return &b;
}  

并删除所有与a_instanceb_instance 有关的代码。

【讨论】:

  • 感谢您复制我的回答。
  • @LihO 对不起。我不知道使用诸如here 描述的通用技术改进答案被认为是复制。 FWIW 您的答案更加详细,并在我打开编辑窗口时发布,因为我正在做其他事情并在等待一些缓慢的测试时进行 SO。
【解决方案2】:

B 构造函数首先调用A 构造函数。这将替换您已经创建的 a_instance

这种构造函数的链接在标准中得到了很好的定义。基类总是首先被调用,这样派生的构造函数就可以保证在一个有效的基类对象上工作。

【讨论】:

  • 所以 this 中的thisA 构造函数中变为B
  • 出于好奇,如果你想避免这种情况 - 你会怎么做?
  • @staticx 你不能,因为类型B 类型A
  • 我猜你可以按照这里的描述做一些事情,不是吗? parashift.com/c++-faq/final-classes.html
  • @staticx 你可以,但是你不能从A 派生出来,整个问题变得毫无意义。
【解决方案3】:

您遇到的问题是由设计错误引起的,这是基于A 的构造函数使用this 初始化静态成员。此构造函数的主体不仅在您创建 A 的实例时被调用,而且在您创建其任何派生类的实例时被调用:

A() { /* ... */ a_instance = this; }

所以当你创建一个B类型的实例时,在B的构造函数的主体被执行之前,A的构造函数的主体首先被执行——这会用@覆盖成员a_instance 987654329@ 在B 类型实例的上下文中,即它使a_instance 指向这个B 类型的新实例。


您可以做的是在getInstance 方法中放置一个静态变量:

class A
{
public:
    static A* getInstance() {
        static A s;                 // <-- instantiated upon first call
        return &s;
    }
    void virtual foo() { std::cout << "From base class" << std::endl; }

protected:
    A() { }                         // <-- protected constructor
    ~A() { }
    A(const A&);                    // <-- protected copy constructor
    A& operator=(const A&);         // <-- protected assignment operator
};

然后B:

class B : public A
{
public:
    static B* getInstance() {
        static B s;                 // <-- instantiated upon first call
        return &s;
    }
    void virtual foo() { std::cout << "From derived class" << std::endl; }

protected:
    B() { }                         // <-- protected constructor
    ~B() { }
    B(const B&);                    // <-- protected copy constructor
    B& operator=(const B&);         // <-- protected assignment operator
};

和可能的用法:

int main() {
    A::getInstance()->foo();
    B::getInstance()->foo();
}

输出:

来自基类
从派生类

【讨论】:

  • 杰出的解释!。谢谢!。
  • @JohnX:不客气。请注意,将复制构造函数和赋值运算符设为私有可确保此类只有 1 个实例。
  • 同意。再次感谢!
【解决方案4】:

B 构造函数调用A 构造函数...

【讨论】:

    猜你喜欢
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    • 2015-03-20
    • 2022-08-20
    • 2013-06-13
    • 2014-05-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多