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 は 5 ではなく 1 です。toStringはage変数を読み取ることができませんか? /* */ Cat クラスの toString メソッドを開くと、年齢は 5 になります。

(私の英語はあまり上手ではありません。ありがとう)

4

3 に答える 3

2

問題は、変数 in にCat書き込んでいるのに対し、age変数 inをCat読み取りtoString()、のコンストラクターで に初期化されていることです。ageAnimalAnimal1

これを解決するには、のメンバー変数を初期化するために使用されるパラメーターをAnimal受け入れる別のコンストラクターを提供できます。ageAnimalage

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別の解決策は、年齢を設定するクラスにセッター メソッドを追加することです。その後、 のコンストラクターで呼び出して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;
    }
};

そして、クラス定義でCatの変数を削除します。ageこのアプローチは単純ですが、「脆い基本クラス」の問題に遭遇するリスクが高くなります。したがって、前述の問題が発生しにくいため、前者のソリューションをお勧めします。IMHOは、「実装ではなくインターフェースに対して書き込む」という原則に固執します。

于 2013-11-04T04:35:23.900 に答える
1

問題は、によって使用されるのではなく、コンストラクターで設定Cat::ageしていることです。CatAnimal::ageAnimal::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 に答える