我有代码:
#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!
(我的英语不太好。谢谢)
答案 0 :(得分:1)
问题是您在Cat::age
构造函数中设置了Cat
,而不是Animal::age
使用的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;
}
};
答案 1 :(得分:1)
问题是Cat
正在写age
中的Cat
变量,而toString()
读取age
中的Animal
变量,其中Animal
的构造函数初始化为1
。
要解决此问题,您可以为Animal
提供另一个构造函数,该构造函数接受age
参数,该参数用于初始化Animal
的{{1}}成员变量。
age
UPDATE:另一种解决方案是在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
};
类中添加一个设置其年龄的setter方法。然后,您可以在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);
}
};
的{{1}}成员Animal
age
在类定义中删除protected
的{{1}}变量。尽管它很简单,但这种方法在遇到"brittle base class" problem时会带来更大的风险。因此,我推荐前一种解决方案,因为它不太容易出现上述问题,而恕我直言更好地坚持“针对接口而不是实现”原则。
答案 2 :(得分: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;
}