我希望我放置的 private 的 int Medals 不能有负值,但我不知道如何与构造函数一起实现该封装。我这样做是为了让每个运动员类型都继承 Athlete 构造函数,但我不知道在哪里调用 setMedals 函数才能使其工作。
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
class Athlete {
private:
int Medals;
public:
string Name;
void setMedals(int newMedals) {
if (newMedals >= 0)
Medals = newMedals;
}
int getMedals() const{
return Medals;
}
virtual string getDescription() = 0;
Athlete(string _Name, int _Medals) : Name(_Name), Medals(_Medals) {}
};
class Footballer : public Athlete {
public:
string getDescription() {
return "Footballer ";
}
Footballer(string Name, int Medals) : Athlete(Name, Medals) {}
};
class Basketballer : public Athlete {
public:
string getDescription() {
return "Basketballer ";
}
Basketballer(string Name, int Medals) : Athlete(Name, Medals) {}
};
ostream& operator <<(ostream& output, vector<Athlete*> athletes) {
for (int i = 0; i < athletes.size(); i++) {
output << athletes[i]->getDescription() << " " << athletes[i]->Name << ": " << athletes[i]->getMedals() << " Medals" << endl;
}
return output;
}
void printAthletes(vector<Athlete*> athletes) {
sort(athletes.begin(), athletes.end(), [](Athlete* a, Athlete* b) {
return a->getMedals() > b->getMedals(); });
cout << athletes;
}
int main() {
Footballer Andrew("Andrew", 3), Jack("Jack", 4);
Basketballer David("David", 5), Rob("Rob", 1);
vector<Athlete*> Athlete = { &Andrew, &Jack, &David, &Rob };
printAthletes(Athlete);
return 0;
}
我希望你能理解我的问题,因为我不知道还能用什么方式来表达它。
从函数来看:
void setMedals(int newMedals) {
if (newMedals >= 0)
Medals = newMedals;
}
看来您想在
Medals
为正值时设置其值,否则不执行任何操作。为此,您首先必须为 Medals
提供不同的初始化程序。当提供给构造函数的值错误时,它将采用一些值。请注意,您可以使成员 unsigned
无论如何它应该只存储正值。最终,您可以在 setMedals
构造函数中调用 Athlete
。通常,最好在构造函数中初始化成员而不是赋值。然而,当你想要初始化+可选赋值时,两者都做就可以了:
class Athlete {
private:
unsigned Medals = 0; // <- initializer here
public:
string Name;
void setMedals(int newMedals) {
if (newMedals >= 0)
Medals = newMedals;
}
int getMedals() const{
return Medals;
}
virtual string getDescription() = 0;
Athlete(string _Name, int _Medals) : Name(_Name) { // <- no initializer here
setMedals(_Medals); // <- call the setter
}
};
因为构造函数没有为
Medals
提供初始化程序,所以使用类内初始化程序 (= 0
)。该成员是 unsigned
并且只能取正值,但是当您想要检查 setMedals
的子类或调用者提供的值是否为负数时,必须对参数进行签名。
tl;博士: 在构造函数内调用非虚函数通常没问题,尽管在处理较大的对象时我会注意这一点。 所以,像这样的事情应该做:
class Athlete
{
private:
unsigned medals{0};
public:
string name;
void setMedals(int m) //or just use unsigned...
{
if (m >= 0)
medals = m;
}
unsigned getMedals() const{return medals;}
virtual string getDescription() = 0; //should be const maybe?
Athlete(string n, int m) : name(move(n))
{
setMedals(m);
}
};
至于扩展答案:
第一个答案,即使用 unsigned int 就足够了。 然而,人们可能想知道 getter 和 setter 的全部目的是什么,如果它们实际上是访问变量的传递,因此不存在真正的封装。
因此,人们可以简单地考虑这样的事情(为了简洁起见,简化了界面):
struct Athlete
{
unsigned medals;
};
如果需要某种输入验证/处理,例如
medals
不能超过10,可以考虑使用setter和getter,例如
class Athlete
{
public:
explicit Athlete(unsigned m)
: medals {clamp(m, 0, 10)}
//or throw from constructor
//depedns what one wants really
{}
unsigned getMedals() const { return medals; }
void setMedals(unsigned m) { medals = clamp(m, 0, 10); }
//again, you may throw or do anything else
//clamping is just an example
private:
unsigned medals;
};
但是,这里出现了一个关于对象责任的问题。 也许不是
Athlete
应该关心奖牌的数量(或值代表的任何内容),但 Medals
变量本身应该是不同的类型,保持其自身的不变性。
如果有人决定采用这种方法,它可能看起来像这样:
template <typename T, T LO, T HI>
class LimitedInt
{
//all the needed operations
};
struct Athlete
{
using Medals = LimitedInt<unsigned, 0, 10>;
Medals medals;
};
不幸的是,这里没有简单的答案,哪个更好或更差,这取决于多种因素,更不用说使用的代码风格和框架就是其中之一,例如QT 按照惯例广泛使用 getter 和 setter。
您可以使用无符号值来确保变量不会有负值。
unsigned int Medals {0};
设置的函数为:
void setMedals(unsigned int newMedals)
{
Medals = newMedals
}
我认为你应该在你的构造函数中将奖牌值默认为0,这样如果它是负数,它就不会分配给你的财产。 然后在构造函数方法中,您可以调用“setMedals”方法。