C++ | Derived class 正在访问基 class 的私有成员而不是它自己的私有成员

C++ | Derived class is accessing private members of the base class rather than its own private members

很抱歉,如果这是一个明显的问题,但我已经四处搜索,但我仍然不清楚如何解决这个问题。这是我的代码:

#include <iostream>
#include <string>
using namespace std;

class PermMagnet {
public:
    string name;
    int ac_rating;
    int dc_rating;
    int mass_kg;
    int age;
    PermMagnet(){
        // default constructor
        name = "";
        ac_rating = 0; dc_rating = 0;
        mass_kg = 0; age = 0;
    }
    PermMagnet(string c_name, int c_ac_rating, int c_dc_rating, int c_mass_kg, int c_age){
        // parameterised constructor
        name = c_name;
        ac_rating = c_ac_rating;
        dc_rating = c_dc_rating;
        mass_kg = c_mass_kg;
        age = c_age;
    }
    string get_owner(){
        return owner;
    }
    string get_classifier(){
        return classifier;
    }
    int get_coil_count(){
        return coil_num;
    }
protected:
    string location = "facility hall";
private:
    string owner = "Unspecified Staff";
    string classifier = "MAG-DP-";
    const int coil_num = 2;
};

class ElecMagnet : public PermMagnet {
public:
    // inherit base class constructors
    using PermMagnet::PermMagnet;

    string get_location(){
        return location;
    }

private:
    string owner = "Specified Staff";
    string classifier = "MAG-QD-";
    const int coil_num = 4;
};

int main() {

    // Create object using default constructor
    PermMagnet perm1;
    cout << "'perm1' age: " << perm1.age << endl;

    // Create object using parameterised constructor
    PermMagnet perm2("PermMagnet 2", 380, 400, 1500, 35);
    cout << "'perm2' age: " << perm2.age << " | 'perm2' name: " << perm2.name << endl;
    cout << "Owner of 'perm2': " << perm2.get_owner() << endl;
    cout << "Upper current bound of 'perm2': " << perm2.get_current_limit("upper") << "A" << endl;
    cout << "Number of coils in 'perm2': " << perm2.get_coil_count() << endl << endl;

    // Create a ElecMagnet (derived class) object
    ElecMagnet elec1("ElecMagnet 1", 170, 200, 850, 27);
    cout << elec1.get_classifier() << endl;
    cout << elec1.get_coil_count() << endl;

    return 0;
}

这段代码的输出是:

'perm1' age: 0
'perm2' age: 35 | 'perm2' name: PermMaget 2
Owner of 'perm2': Unspecified Staff
Upper current bound of 'perm2': 780A
Number of coils in 'perm2': 2

MAG-DP-
2

Process finished with exit code 0

如您所见,我希望“owner”、“classifier”和“coil_num”成为用户无法更改的私有成员。这些也因所讨论的 class 而异。

问题:

问题出在输出的最后两行。当派生的 class (ElecMagnet) 继承 return 这些成员的 public 功能时,它 return 是基础 class 的成员;不是它自己的。您可以看到这一点,因为它 return 是 PermMagnet class.

的“classifier”和“coil_num”

有谁知道派生的 class 为什么会这样?它不应该访问它自己的私有成员而不是基础吗?

私有成员只能被class或好友的成员函数访问。 C++ 的行为不像 Python,其中根据当前指针动态执行变量搜索 this (self).

发生这种情况是因为您仍在调用基 class 的方法,它不知道派生 class 的成员变量,因此不会使用它们。 要存档您想要的内容,您需要在派生 class 中覆盖 get_classifier(),以便通过 ElecMagnet 引用调用它会调用派生方法。当通过 PermMagnet 引用在 ElecMagnet 值上调用它时,您可以选择创建方法 virtual,甚至调用派生版本。 (通常建议将 classes 设计为继承 virtual。)

或者,根据您的用例,您可以编写显式构造函数,而不是 using 基构造函数,这些构造函数调用具有 classifier 的适当值的(可能受保护的)基构造函数。这将为您完全节省派生 class 中的其他成员变量。

继承使用“是”关系。意思是,你应该可以说 child object “是”基数 object。如果你不能这样说,你就不应该使用继承。

这对于派生 object 的构建意味着它是一个复合体,包含您的基础 object,以及通过继承添加的任何额外位。

您调用了基 object 函数,这意味着它将访问基 object 数据。在派生的 class 中重复数据显然是行不通的,而且是一种不好的做法。如果您需要相同的数据,请使用它,不要重复。

您可以通过让派生的 class 构造函数 总是 首先在初始化部分 调用基础 class 构造函数来实现 [=31] =].您根本不使用初始化部分,这会导致很多效率低下并最终导致错误。

随机位: 所有 class 数据都应该是私有的。 class 的 protected: 部分包含您希望 child 可以 public 访问但不想完全 public 的任何内容。如果您不希望 getter 仅 public 可用,他们可以去那里。我在这里放置了几个构造函数,它们完全是为了 ElecMagnet 而存在的。 using namespace std; 是不好的做法。

代码:

#include <iostream>
#include <string>

class PermMagnet {
 public:
  PermMagnet() = default;
  PermMagnet(std::string c_name, int c_ac_rating, int c_dc_rating,
             int c_mass_kg, int c_age)
      : name(c_name),
        ac_rating(c_ac_rating),
        dc_rating(c_dc_rating),
        mass_kg(c_mass_kg),
        age(c_age) {}  // Use the initialization section

  std::string get_owner() const { return owner; }  // Mark getters as const

  std::string get_classifier() const { return classifier; }

  int get_coil_count() const { return coil_num; }

  std::string get_location() const { return location; }

  int get_age() const { return age; }

  std::string get_name() const { return name; }

 protected:
  PermMagnet(std::string owner, std::string classifier, int coilNum)
      : owner(owner), classifier(classifier), coil_num(coilNum) {}

  PermMagnet(std::string name, int ac_rating, int dc_rating, int mass_kg,
             int age, std::string owner, std::string classifier, int coilNum)
      : name(name),
        ac_rating(ac_rating),
        dc_rating(dc_rating),
        mass_kg(mass_kg),
        age(age),
        owner(owner),
        classifier(classifier),
        coil_num(coilNum) {}

 private:
  std::string owner = "Unspecified Staff";
  std::string classifier = "MAG-DP-";
  const int coil_num = 2;  // const probably unnecessary here, but left it
  std::string location = "facility hall";
  std::string name = "";
  int ac_rating = 0;
  int dc_rating = 0;
  int mass_kg = 0;
  int age = 0;
};

class ElecMagnet : public PermMagnet {
 public:
  ElecMagnet() : PermMagnet("Specified Staff", "MAG-QD-", 4) {}

  ElecMagnet(std::string name, int ac_rating, int dc_rating, int mass_kg,
             int age)
      : PermMagnet(name, ac_rating, dc_rating, mass_kg, age, "Specified Staff",
                   "MAG-QD-", 4) {}

  // NO NEED FOR REPETITIVE PRIVATE SECTION
};

int main() {
  // Create object using default constructor
  PermMagnet perm1;
  std::cout << "'perm1' age: " << perm1.get_age()
            << '\n';  // Prefer '\n' over std::endl

  // Create object using parameterised constructor
  PermMagnet perm2("PermMagnet 2", 380, 400, 1500, 35);
  std::cout << "'perm2' age: " << perm2.get_age()
            << " | 'perm2' name: " << perm2.get_name() << '\n';
  std::cout << "Owner of 'perm2': " << perm2.get_owner() << '\n';
  std::cout << "Number of coils in 'perm2': " << perm2.get_coil_count()
            << "\n\n";

  // Create a ElecMagnet (derived class) object
  ElecMagnet elec1("ElecMagnet 1", 170, 200, 850, 27);
  std::cout << elec1.get_classifier() << '\n';
  std::cout << elec1.get_coil_count() << '\n';

  return 0;
}

请注意,ElecMagnet class 目前只是几个构造函数,您的主函数的行为符合预期。