C++从基类继承的公共方法无法访问派生类中的私有成员变量

C++ public method inherited from base class can not access private member variable in derived class

本文关键字:派生 访问 成员 变量 继承 基类 C++ 方法      更新时间:2023-10-16

我有代码:

#include <iostream>
#include <cstdlib>
using namespace std;
class Animal{
private:
    int age;
public:
    Animal() : age(1) {}
    void toString(){
        cout << "Age: " << age << endl;
    }
};
class Cat : public Animal
{
public:
    Cat() : age(5) {}
    /*
    void toString(){
        cout << "Age: " << age << endl;
    }*/
private:
    int age;
};
int main(){
    Cat tom;
    tom.toString();
    system("pause");
    return 0;
}

但是当我运行程序时,tom 变量的年龄是 1,而不是 5。toString 无法读取年龄变量吗?如果我们在 Cat 类中打开/* */toString 方法,年龄将是 5 !

(我的英语不是很好。谢谢)

问题是CatCat中写入age变量,而toString()Animal中读取age变量,使用Animal的构造函数,初始化为1

为了解决这个问题,你可以为Animal提供另一个构造函数,它接受一个age参数,用于初始化Animalage成员变量。

class Animal{
private:
    int age;
public:
    Animal() : age(1) {}
    Animal(int param_age) : age(param_age) {} // Initialize member variable age with parameter
    void toString(){
        cout << "Age: " << age << endl;
    }
};
class Cat : public Animal
{
public:
    Cat() : Animal(5) {} // Call Animal's constructor that set's the age
};

更新:另一种解决方案是在Animal类中添加一个设置其年龄的 setter 方法。然后,您可以在 Cat 的构造函数中调用它以设置适当的年龄。

class Animal{
private:
    int age;
public:
    Animal() : age(1) {}
    void setAge(int age) { this->age = age; }
    void toString(){
        cout << "Age: " << age << endl;
    }
};
class Cat : public Animal
{
public:
    Cat() {
        setAge(5);
    }
};

另一种选择是使Animal age成员protected

class Animal{
protected:  // THIS
    int age;
public:
    Animal() : age(1) {}
    void toString(){
        cout << "Age: " << age << endl;
    }
};

并删除类定义中的Catage变量。尽管这种方法很简单,但在遇到"脆基类"问题时会给您带来更大的风险。因此,我推荐前一种解决方案,因为它不太容易出现上述问题,并且恕我直言,最好坚持"针对接口而不是实现编写"原则。

问题是您在Cat构造函数中设置Cat::age,而不是Animal::toString使用的Animal::age

Animal::age的可见性更改为受保护。

class Animal {
protected:
    int age;
public:
    Animal() : age(1) {}
    void toString(){
        cout << "Age: " << age << endl;
    }
};

不要重新声明第二个age(变为Cat::age)。相反,请更改 age 的值 ( Animal::age )。

class Cat : public Animal {
public:
    Cat() {
        age = 5;
    }
};

尝试:

#include <iostream>
#include <cstdlib>
using namespace std;
class Animal{
private:
    int age;
public:
    Animal(int a = 1)   // Pass in the age as a parameter.
       : age(a)         // Default to 1.
    {}
    // Prefer generic print function rather than toString()
    friend std::ostream& operator<<(std::ostream& s, Animal const& a) {
        return s << "Age: " << a.age << 'n';  // Prefer 'n' rather than endl
                                               // Unless you really want to flush
                                               // the stream (this is not usually
                                               // the case).
    }
};
class Cat : public Animal
{
public:
    Cat()
       : Animal(5)      // Now you can call the base class constructor
    {}                  // And get it to set 5
private:
    // int age;         // don't have a private copy here.
                        // use the one that is available in the base class.

    // Prefer generic print function rather than toString()
    friend std::ostream& operator<<(std::ostream& s, Cat const& a)
    {
        // Print Cat
        // Then use the Animal priting function to print more information about the object.
        return s << "A Cat: " << static_cast<Animal const&>(*a);
    }
};
int main(){
    Cat tom;
    // tom.toString(); // Don't use a toString() method.
                       // overload operator<< to print to a stream.
                       // If you want to convert to a string the just print
                       // to a string stream.
    std::cout << tom;
    system("pause");
    return 0;
}