【问题标题】:Where are variables stored in Inherited Classes in C++/C++ 继承类中存储的变量在哪里/
【发布时间】:2021-02-08 16:04:42
【问题描述】:

有几个与此类似的问题,但没有人回答我对 C++ 中的继承不了解的问题。

我有一个简单的 Parent 和 Child 类,子类从父类继承。此处的示例只有一个与父级完全相同的子级,但整数 a 的值始终为 0。

classes.h

#ifndef CLASSES_H
#define CLASSES_H

class Parent {
    private:
        int a,b;

    public:
        Parent():a(0), b(0){};
        Parent(int a, int b):a(a), b(b){};

        int getA(){return this->a;}
        int getB(){return this->b;}

};

class Child: public Parent {
    
    public:
        Child(){Parent();};
        Child(int b){Parent(0, b);};
};


#endif

main.cpp

#include "classes.h"
#include <iostream>

using std::cout;
using std::endl;

int main(){
    int a = 2;
    int b = 4;
    Parent parent = Parent(a, b);
    Child child = Child(b);

    cout << "Parent: A=" << parent.getA() << " : B=" << parent.getB() << endl;
    cout << "Child: A=" << child.getA() << " : B=" << child.getB() << endl;

    return 0;
}

output

Parent: A=2 : B=4
Child: A=0 : B=0

我本来希望Child: A=0 : B=4 在第二行,但事实并非如此。

查看其他问题,我知道如果我希望 Child 能够直接访问私有变量,它们需要受到保护或公开。但是我也看到了一个引用

派生类不会继承对私有数据成员的访问权限。但是,它确实继承了一个完整的父对象,其中包含该类声明的任何私有成员

我想了解的是如何“访问”这个父对象。我是否应该将它分配给构造函数中的某些内容,然后重写 getter 类以基本上重定向到父类的 getter 函数?因为这似乎违背了使用 OOP 来捕获父行为的目的。我认为(错误地)构造函数会在子构造函数中设置变量,但如果不是这种情况,那么在子构造函数内部的父构造函数中初始化的那些变量一定是正确的?

我有一个与上面类似的设置,其中一个子级对父级进行了轻微修改(对成员函数进行了一些更改),并且我能够使用受保护的成员变量来处理它,但我不确定它们是否是最佳实践。

【问题讨论】:

  • Child(int b){Parent(0, b);}; 不会像您认为的那样做。您可能希望像这样初始化父级Child(int b) : Parent(0, b) {}
  • 其中一个子节点是对父节点的轻微修改 如果子节点以不同的方式使用父节点的数据成员(修改它们),这可能会破坏父节点中的代码(因为它不“知道”派生的子类)。我会非常小心地使用它,并且只用于异国情调的用例。一种解决方案可能是将这些成员的修改放入可由派生类覆盖的虚拟方法中。 (因此,您可以坚持使用父类中的private 成员,这些成员公开给派生类以作为虚拟方法中的引用参数进行修改。)
  • 另一种选择是重新考虑您的设计:也许,您有两个具有相似但不同行为的类。这些也可以是从相同但抽象的父类派生的兄弟类。因此,父类可能定义了某种独特的接口,但实现只在派生的子类中。
  • 您似乎混合了“变量”和“成员”。 main 中的 int aParent parent 是变量,但 Parent::a 是成员。它们的相似之处在于都有类型和名称,但“它们存储在哪里”的问题有不同的答案。

标签: c++ oop inheritance


【解决方案1】:

有什么问题

子(int b){父(0, b);};

该构造函数创建一个对构造函数来说是本地的父对象,并且在构造函数结束时超出范围。它不是新的子父级(默认构造),而是一个不同的临时父级。

子对象确实有父数据,只是你没有设置而已。

子(int b):父(0, b){}

将 b 传递给基本构造函数以获得您期望的结果

“我想了解的是您如何“访问”这个父对象。”

如果您想直接访问 Parent 的成员数据,您可以使该数据受到保护(甚至公开!),但如果您的问题更多是关于如何让您的 getter 工作以访问该数据,那么它已经是工作,只是您访问的数据不是子构造函数主体中的数据集。

如果您在父构造函数上放置断点并查看会发生什么,也许这将有助于向您自己证明这一点。使用您的代码版本,您应该看到父构造函数被调用了两次。首先在 Childs 构造函数的主体开始之前(在这种情况下通过默认构造函数)发生构造 Child 的基 Parent 时,然后再次从 Child 构造函数的主体中调用。

如果您进行建议的编辑,您只会看到 Parent 构造函数被调用一次。

【讨论】:

  • 在发布此答案之前我没有阅读评论 - 我现在看到第一条评论中提出了同样的观点。
【解决方案2】:

我认为您需要了解 private 应该实现的目标。

如果父类具有明确希望保护派生类不访问的变量(状态),则将它们声明为私有。这个限制没有(简单或可读),它专门用于阻止派生类直接访问这些值。通常存在可用于更新或检索这些私有值的受保护或公共函数 - 这允许父类有机会将实现与派生类隔离。

如果您希望派生类能够直接与数据交互,则将其声明为受保护 - 这就是受保护的目的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 2018-02-01
    • 2023-02-09
    • 2010-09-10
    • 2013-04-19
    相关资源
    最近更新 更多