3

我有代码:

#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变量的age是1,不是5。toString是不是不能读取age变量?如果我们打开 Cat 类中的 /* */ toString 方法,年龄将是 5 !

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

4

3 回答 3

2

问题是Cat写入age变量 in Cat,而toString()读取age变量 in Animal,使用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);
    }
};

另一种选择是 makeAnimalage成员protected

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

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

于 2013-11-04T04:35:23.900 回答
1

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

将 的可见性更改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;
    }
};
于 2013-11-04T04:29:17.167 回答
0

尝试:

#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;
}
于 2013-11-04T04:40:59.440 回答