C++ 继承:为什么继承的变量和提供的变量在行为上存在差异?

C++ 继承:为什么继承的变量和提供的变量在行为上存在差异?,c++,inheritance,C++,Inheritance,例如,在这段代码中,如果注释掉了行[a],则输出为0 inh2.cpp 我有两个问题: 在上述情况下,ab->x如何解析为10?对象的类型为类别B,因此其值应为0 为什么注释行[a]会改变代码的行为?我的推理是,x无论如何都会被继承,这将导致相同的行为 我对上述问题1的推理: ab指向类B对象的内存位置。它是一个物理对象,因为所有变量及其值都分配给内存 此对象中的变量x存储值0 当ab->x完成时,ab告诉我们对象的内存位置,然后我们去查看它,发现x是0。所以我们应该打印0 我哪里错了 是

例如,在这段代码中,如果注释掉了
行[a]
,则输出为0

inh2.cpp

我有两个问题:

  • 在上述情况下,
    ab->x
    如何解析为
    10
    ?对象的类型为
    类别B
    ,因此其值应为
    0
  • 为什么注释
    行[a]
    会改变代码的行为?我的推理是,
    x
    无论如何都会被继承,这将导致相同的行为

  • 我对上述问题1的推理:


    • ab
      指向
      类B
      对象的内存位置。它是一个物理对象,因为所有变量及其值都分配给内存

    • 此对象中的变量
      x
      存储值
      0

    • ab->x
      完成时,ab告诉我们对象的内存位置,然后我们去查看它,发现x是0。所以我们应该打印0

    我哪里错了

  • 是的,它的类型是
    B
    ,但您将其指定为指向
    a
    的指针,因此它使用了在a上定义的
    x
    (当我们处理指向a的指针时,我们不知道
    B
    甚至存在,即使这是您分配的)

  • 当您注释掉该行时,在构造阶段,首先调用
    A
    s构造函数,然后调用
    B
    s构造函数,该构造函数将
    x
    (在其基类中)设置为0。此时只有一个
    x
    ,最后调用Bs构造函数

  • 是的,它的类型是
    B
    ,但您将其指定为指向
    a
    的指针,因此它使用了在a上定义的
    x
    (当我们处理指向a的指针时,我们不知道
    B
    甚至存在,即使这是您分配的)

  • 当您注释掉该行时,在构造阶段,首先调用
    A
    s构造函数,然后调用
    B
    s构造函数,该构造函数将
    x
    (在其基类中)设置为0。此时只有一个
    x
    ,最后调用Bs构造函数


  • 进行一些小的修改:

    #include <iostream>
    
    using namespace std;
    
    class A {
    public:
        int x;
        A()
            :x(10)
        {
            std::cout << __FUNCTION__ << std::endl;
            std::cout << x << std::endl;
        }
        virtual ~A() {}
    };
    
    class B : public A {
    public:
        int x;  // <--------- [a]
        B()
            :A()
            ,x(0)
        {
            std::cout << __FUNCTION__ << std::endl;
            std::cout << x << std::endl;
        }
    };
    
    int main() {
        A* ab = new B;
        cout << "ab->x: " << ab->x << endl;
        cout << "ab->A::x " << ab->A::x << endl;
    
        B* b = dynamic_cast<B*>(ab);
        cout << "b->x: " << b->x << endl;
        cout << "b->A::x " << b->A::x << endl;
        cout << "b->B::x " << b->B::x << endl;
    }
    
    这表明:

    • ab->x
      指的是
      A::x
      ,因为
      ab
      属于
      A*
      类型,并且不存在
      虚拟
      变量。如果需要多态性,则必须编写一个
      虚拟int get_x()const
      方法
    • B::x
      隐藏
      A::x
      。这是个坏主意,应该避免。考虑为成员变量使用一个更有意义的名称,并确定是否可以在引入新的变量之前重用基类的变量。
    • 强制转换到a
      B*
      允许您访问
      B
      的成员以及
      a
      。这应该是不言自明的

      • 进行一些小的修改:

        #include <iostream>
        
        using namespace std;
        
        class A {
        public:
            int x;
            A()
                :x(10)
            {
                std::cout << __FUNCTION__ << std::endl;
                std::cout << x << std::endl;
            }
            virtual ~A() {}
        };
        
        class B : public A {
        public:
            int x;  // <--------- [a]
            B()
                :A()
                ,x(0)
            {
                std::cout << __FUNCTION__ << std::endl;
                std::cout << x << std::endl;
            }
        };
        
        int main() {
            A* ab = new B;
            cout << "ab->x: " << ab->x << endl;
            cout << "ab->A::x " << ab->A::x << endl;
        
            B* b = dynamic_cast<B*>(ab);
            cout << "b->x: " << b->x << endl;
            cout << "b->A::x " << b->A::x << endl;
            cout << "b->B::x " << b->B::x << endl;
        }
        
        这表明:

        • ab->x
          指的是
          A::x
          ,因为
          ab
          属于
          A*
          类型,并且不存在
          虚拟
          变量。如果需要多态性,则必须编写一个
          虚拟int get_x()const
          方法
        • B::x
          隐藏
          A::x
          。这是个坏主意,应该避免。考虑为成员变量使用一个更有意义的名称,并确定是否可以在引入新的变量之前重用基类的变量。
        • 强制转换到a
          B*
          允许您访问
          B
          的成员以及
          a
          。这应该是不言自明的

        关于#1,在运行时,已知对象的类型为
        B
        ,那么它不应该解析为0吗?@Lazer,谁知道?我们知道它是一个B,但是我们的指针指向一个a,这就是我们将要使用的。为了测试这一点,向B添加一个新成员,
        inty。现在执行
        ab->y
        。当
        y
        不是
        a
        的成员
        ab
        指向
        类B
        的对象的内存位置时,将出现编译器错误。它是一个物理对象,在这个意义上,所有变量及其值都被分配给内存并存在。此对象中的变量
        x
        存储值
        0
        。当
        ab->x
        完成时,ab告诉我们对象的内存位置,然后我们去查看它,发现x是
        0
        。所以我们应该打印
        0
        。不知道我在这里错过了什么?[we=compiler]这里有两个变量<代码>A::x
        B::x
        。如果
        p
        是指向
        a
        的指针,那么
        p->x
        指的是
        a::x
        。如果它是指向
        B
        ,则
        p->x
        B::x
        p->a::x
        a::x
        。没有办法访问<代码>::x/c> >只给出一个指向<代码> A/<代码>的指针,因为一般不能保证有一个<代码> B<代码>。@ LaZe:不是,C++中的运行时多态性只适用于虚拟函数。不适用于变量。关于#1,在运行时,已知对象的类型为
        B
        ,那么它不应该解析为0吗?@Lazer,谁知道?我们知道它是一个B,但是我们的指针指向一个a,这就是我们将要使用的。为了测试这一点,向B添加一个新成员,
        inty。现在执行
        ab->y
        。当
        y
        不是
        a
        的成员
        ab
        指向
        类B
        的对象的内存位置时,将出现编译器错误。它是一个物理对象,在这个意义上,所有变量及其值都被分配给内存并存在。此对象中的变量
        x
        存储值
        0
        。当
        ab->x
        完成时,ab告诉我们mem
        #include <iostream>
        
        using namespace std;
        
        class A {
        public:
            int x;
            A()
                :x(10)
            {
                std::cout << __FUNCTION__ << std::endl;
                std::cout << x << std::endl;
            }
            virtual ~A() {}
        };
        
        class B : public A {
        public:
            int x;  // <--------- [a]
            B()
                :A()
                ,x(0)
            {
                std::cout << __FUNCTION__ << std::endl;
                std::cout << x << std::endl;
            }
        };
        
        int main() {
            A* ab = new B;
            cout << "ab->x: " << ab->x << endl;
            cout << "ab->A::x " << ab->A::x << endl;
        
            B* b = dynamic_cast<B*>(ab);
            cout << "b->x: " << b->x << endl;
            cout << "b->A::x " << b->A::x << endl;
            cout << "b->B::x " << b->B::x << endl;
        }
        
        A
        10
        B
        0
        ab->x: 10
        ab->A::x 10
        b->x: 0
        b->A::x 10
        b->B::x 0