Maaf jika ini jelas tetapi saya telah mencari-cari dan saya masih tidak jelas tentang bagaimana menyelesaikan masalah ini. Ini kode saya:

#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;
}

Output dari kode ini adalah:

'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

Seperti yang Anda lihat, saya ingin "pemilik", "pengklasifikasi" dan "coil_num" menjadi anggota pribadi yang tidak dapat diubah oleh pengguna. Ini juga bervariasi tergantung pada kelas yang bersangkutan.

Masalah:

Masalahnya adalah dua baris terakhir dari output. Ketika kelas turunan (ElecMagnet) mewarisi fungsi publik yang mengembalikan anggota ini, ia mengembalikan anggota kelas dasar; bukan miliknya. Anda dapat melihat ini karena mengembalikan "classifier" dan "coil_num" dari kelas PermMagnet.

Adakah yang tahu mengapa kelas turunan berperilaku seperti ini? Bukankah seharusnya mengakses anggota pribadinya sendiri daripada pangkalan?

0
Cato 23 Desember 2020, 17:56

3 jawaban

Jawaban Terbaik

Warisan menggunakan hubungan "adalah". Artinya, Anda harus dapat mengatakan bahwa objek anak "adalah" objek dasar. Jika Anda tidak bisa mengatakan ini, Anda seharusnya tidak menggunakan warisan.

Apa artinya ini untuk membangun objek turunan adalah bahwa itu adalah komposit, berisi objek dasar Anda, dan bit tambahan apa pun yang telah ditambahkan melalui pewarisan.

Anda memanggil fungsi objek dasar, yang berarti akan mengakses data objek dasar. Mengulangi data di kelas turunan jelas tidak berhasil, dan merupakan praktik yang buruk. Jika Anda membutuhkan data yang sama, gunakan dan jangan ulangi.

Anda melakukannya dengan meminta konstruktor kelas turunan Anda selalu memanggil konstruktor kelas dasar terlebih dahulu di bagian inisialisasi. Anda tidak menggunakan bagian inisialisasi sama sekali, ini dapat menyebabkan banyak inefisiensi dan akhirnya kesalahan.

Bit acak: Semua data kelas harus bersifat pribadi. Bagian protected: dari kelas menampung apa pun yang Anda inginkan agar anak memiliki akses publik, tetapi tidak ingin dipublikasikan sepenuhnya. Jika Anda tidak ingin getter tersedia untuk umum, mereka bisa pergi ke sana. Saya menempatkan beberapa konstruktor yang ada hanya untuk ElecMagnet di sini. using namespace std; adalah praktik yang buruk.

Kode:

#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;
}

Perhatikan bahwa kelas ElecMagnet saat ini sekarang hanya beberapa konstruktor, dan fungsi utama Anda berperilaku seperti yang diharapkan.

0
sweenish 23 Desember 2020, 15:45

Anggota pribadi hanya dapat diakses oleh fungsi anggota dari kelas atau teman yang sama. C++ tidak berperilaku seperti, misalnya, Python, di mana pencarian variabel dilakukan secara dinamis tergantung pada pointer saat ini this (self).

0
alex_noname 23 Desember 2020, 15:07

Ini terjadi karena Anda masih memanggil metode kelas dasar, yang tidak dapat mengetahui tentang variabel anggota dari kelas turunan dan dengan demikian tidak akan menggunakannya. Untuk mengarsipkan apa yang Anda inginkan, Anda perlu mengganti get_classifier() di kelas turunan sehingga memanggilnya melalui referensi ElecMagnet akan memanggil metode turunan. Anda dapat secara opsional membuat metode virtual, bahkan untuk memanggil versi turunan, saat menjalankannya pada nilai ElecMagnet melalui referensi PermMagnet. (Membuat kelas yang dirancang untuk pewarisan virtual umumnya disarankan.)

Atau, bergantung pada kasus penggunaan Anda, alih-alih using konstruktor dasar, Anda dapat menulis konstruktor eksplisit yang memanggil konstruktor dasar (mungkin dilindungi) dengan nilai yang sesuai untuk classifier. Ini akan menghemat variabel anggota tambahan di kelas turunan sepenuhnya.

0
Reizo 23 Desember 2020, 15:10