【问题标题】:variables scoping when inheriting继承时的变量作用域
【发布时间】:2009-11-05 17:37:10
【问题描述】:

我在 C++ 中有两个类,其中一个继承自另一个:

class A {
public: 
    virtual void Initialize(){
        m_MyString = "Default value";
    }

protected: 
     string m_MyString;
}

class B : public A {
public: 
    void Initialize(){ 
       A::Initialize(); 
       m_MyString = "New Value";
    }
}

上面的B类和这个有区别吗?

class B : public A {
public: 
    void Initialize(){ 
       A::Initialize(); 
       A::m_MyString = "New Value";
    }
}

似乎使用范围运算符会导致字符串有垃圾,对吗?我在想当它覆盖时,A::m_MyString 与 B::m_MyString 不同。这甚至有意义吗?

我看到变量在 A 中设置,然后当我们返回 B 时,有垃圾。这与“隐藏”与覆盖有关吗?

【问题讨论】:

  • 在我看来你没有覆盖 m_MyString;它仅在 A 中定义。如果是这种情况,它应该可以正常工作。是这样吗?
  • 您尝试过干净的构建吗?当您的依赖项已过期并且需要重新编译 B 而不是时,也会发生这种情况。

标签: c++ inheritance scoping


【解决方案1】:

您的代码在很多方面都无效。它应该看起来像:

class A { // << errors were here
public: 
    virtual void Initialize(){
        m_MyString = "Default value";
    }

protected: 
     string m_MyString;
}; // << lost ;

class B : public A // << errors were here
{
public: 
    virtual void Initialize(){  // << virtual
       A::Initialize(); // has no effect in the end

       A::m_MyString = "New Value"; // same as `m_MyString = "New Value";`
    }
}; // << lost ;

在上面的代码中,m_MyString 没有区别。发布有错误的实际代码。

如果您的代码如下所示:

class B : public A
{
public: 
    virtual void Initialize(){
       // here is a difference
       A::m_MyString = "New Value"; 
       m_MyString = "New Value";
    }
protected: 
     string m_MyString; // !!! overridden
};

那么就有区别了,因为B 有两个m_MyString 实例:A::m_MyStringB::m_MyString

【讨论】:

    【解决方案2】:

    你是从 A 的构造函数调用 Initialize() 吗?

    不推荐在构造函数中调用虚方法。例如,如果 A 的构造函数看起来像

    A::A() {
      Initialize();
    }
    

    B 的 Initialize 方法永远不会被调用。

    查看您的实际代码会有很大帮助。

    【讨论】:

      【解决方案3】:

      这两个版本的 B 类没有区别。那是你看到垃圾的真实代码吗?

      【讨论】:

        【解决方案4】:

        编译器应该告诉你是否从构造函数调用虚函数。但如果不是,那肯定是个问题。

        我认为你可以在派生类中创建一个最终的虚函数,但也许不能。无论您是否显式定义范围,变量都应该相同,除非您在派生类中有同名变量。

        【讨论】:

        • 在 C++ 中,虚函数永远是虚函数。没有办法让它成为“最终”。
        【解决方案5】:

        如果您的代码是这样的:

        using namespace std;
        
        class A 
        {
            public:
                virtual void Initialize()
                {
                    m_MyString = "Default value";
                }
        
            protected:
                string m_MyString;
        };
        
        class B : public A 
        {
            public:
                void Initialize()
                {
                    A::Initialize();
                    m_MyString = "New Value";
                }
        
                void display()
                {
                    cout<<m_MyString<<endl;
                }
        };
        
        int main()
        {
            B b;
            A a;
        
            b.Initialize();
            b.display();
        
            return 0;
        }
        

        那么您在问题中描述的 B 类的两个版本之间没有区别。我添加了显示功能只是为了使值清晰。根据您给出的类的定义, m_MyString 没有被覆盖。因此 m_MyString 变量将被分配“新值”,即 A 类和 B 类将共享变量 m_MyString。

        如果你覆盖 B 类中的 m_MyString 像

        class B : public A 
        {
            public:
                void Initialize()
                {
                    A::Initialize();
                    m_MyString = "New Value";
                }
        
            void display()
            {
                cout<<m_MyString<<endl;
            }
        
            protected:
                string m_MyString;
        };
        

        那么 B::m_MyString 的值将包含“新值”,而 A::m_MyString 的值将包含“默认值”。

        【讨论】:

          【解决方案6】:

          似乎使用范围运算符会导致字符串有垃圾,对吗?

          不,这应该有效,并且在调用 b.Initialize() 后 m_MyString 将具有“新值”。

          我在想,当它覆盖时,A::m_MyString 与 B::m_MyString 不同。做 这甚至有意义吗?

          不,当一个类 B 继承另一个类 A 时,类 B 的对象将具有两者的数据成员的并集。在这种情况下,只有一个 m_MyString 是 A::m_MyString。

          我看到变量在 A 中设置,然后当我们返回 B 时,有垃圾。 这与“隐藏”与覆盖有关吗?

          不,m_MyString 只有一个实例。

          你肯定需要阅读这篇文章 - http://www.openrce.org/articles/files/jangrayhood.pdf

          【讨论】:

            猜你喜欢
            • 2015-11-09
            • 2011-02-17
            • 1970-01-01
            • 1970-01-01
            • 2018-03-12
            • 2012-11-19
            • 2015-12-09
            • 2014-10-06
            • 2016-06-01
            相关资源
            最近更新 更多