与构造函数一起封装
Encapsulation along with constructors
我希望我设置为 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;
}
我希望你能理解我的问题,因为我不知道如何表达它。
您可以使用无符号值来确保变量不会有负值。
unsigned int Medals {0};
设置函数为:
void setMedals(unsigned int newMedals)
{
Medals = newMedals
}
我认为您应该在构造函数中将奖牌值默认为 0,这样如果它是负数,就不会分配给您的 属性。
然后在你的构造方法中,你可以调用你的“setMedals”方法。
希望对您有所帮助。
来自函数:
void setMedals(int newMedals) {
if (newMedals >= 0)
Medals = newMedals;
}
看来您想将 Medals
的值设置为正值,否则什么也不做。为此,您首先必须为 Medals
提供不同的初始化程序。当提供给构造函数的值错误时,它将采用一些值。请注意,您可以使成员 unsigned
无论如何它应该只存储正值。最终,您可以在 Athlete
构造函数中调用 setMedals
。通常最好在构造函数中初始化成员而不是赋值。但是,正如你想要的初始化+可选赋值,两者都做是可以的:
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
提供初始值设定项,所以使用了 in-class 初始值设定项 (= 0
)。该成员是 unsigned
并且只能取正值,但是由于您要检查 setMedals
的子类或调用者提供的值是否为负值,因此必须对参数进行签名。
tl;博士:
在构造函数中调用 non-virtual 函数通常没问题,尽管在处理较大的对象时我会注意它。
所以,应该这样做:
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);
}
};
至于扩展答案:
首先,一个简短的免责声明。我想知道我是否应该在这里回答这个问题,或者将它标记给版主以将主题主题移动到软件工程或其他类似的 SE 站点,因为讨论很可能会转向一般的“架构”。
如果版主、用户或 OP him/herself 喜欢,请这样做。
话虽如此,正题:第一个答案,即使用unsigned int就可以了。
然而,人们可能想知道 getters 和 setters 的全部目的是什么,如果它们实际上是 pass-through 来访问变量,那么就没有真正的封装。
出于这个原因,人们可以简单地考虑这样的事情(为简洁起见简化了界面):
struct Athlete
{
unsigned medals;
};
如果需要某种输入 validation/processing,例如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
变量 iself 应该是保持其自身不变性的不同类型。
如果决定采用这种方法,它可能看起来像这样:
template <typename T, T LO, T HI>
class LimitedInt
{
//all the needed operations
};
struct Athlete
{
using Medals = LimitedInt<unsigned, 0, 10>;
Medals medals;
};
不幸的是,这里没有简单的答案哪个更好或更差,这取决于多种因素,更不用说代码风格和使用的框架是其中之一,例如QT 按照惯例广泛使用 getters 和 setters。
我希望我设置为 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;
}
我希望你能理解我的问题,因为我不知道如何表达它。
您可以使用无符号值来确保变量不会有负值。
unsigned int Medals {0};
设置函数为:
void setMedals(unsigned int newMedals)
{
Medals = newMedals
}
我认为您应该在构造函数中将奖牌值默认为 0,这样如果它是负数,就不会分配给您的 属性。 然后在你的构造方法中,你可以调用你的“setMedals”方法。
希望对您有所帮助。
来自函数:
void setMedals(int newMedals) {
if (newMedals >= 0)
Medals = newMedals;
}
看来您想将 Medals
的值设置为正值,否则什么也不做。为此,您首先必须为 Medals
提供不同的初始化程序。当提供给构造函数的值错误时,它将采用一些值。请注意,您可以使成员 unsigned
无论如何它应该只存储正值。最终,您可以在 Athlete
构造函数中调用 setMedals
。通常最好在构造函数中初始化成员而不是赋值。但是,正如你想要的初始化+可选赋值,两者都做是可以的:
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
提供初始值设定项,所以使用了 in-class 初始值设定项 (= 0
)。该成员是 unsigned
并且只能取正值,但是由于您要检查 setMedals
的子类或调用者提供的值是否为负值,因此必须对参数进行签名。
tl;博士: 在构造函数中调用 non-virtual 函数通常没问题,尽管在处理较大的对象时我会注意它。 所以,应该这样做:
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);
}
};
至于扩展答案: 首先,一个简短的免责声明。我想知道我是否应该在这里回答这个问题,或者将它标记给版主以将主题主题移动到软件工程或其他类似的 SE 站点,因为讨论很可能会转向一般的“架构”。 如果版主、用户或 OP him/herself 喜欢,请这样做。
话虽如此,正题:第一个答案,即使用unsigned int就可以了。 然而,人们可能想知道 getters 和 setters 的全部目的是什么,如果它们实际上是 pass-through 来访问变量,那么就没有真正的封装。
出于这个原因,人们可以简单地考虑这样的事情(为简洁起见简化了界面):
struct Athlete
{
unsigned medals;
};
如果需要某种输入 validation/processing,例如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
变量 iself 应该是保持其自身不变性的不同类型。
如果决定采用这种方法,它可能看起来像这样:
template <typename T, T LO, T HI>
class LimitedInt
{
//all the needed operations
};
struct Athlete
{
using Medals = LimitedInt<unsigned, 0, 10>;
Medals medals;
};
不幸的是,这里没有简单的答案哪个更好或更差,这取决于多种因素,更不用说代码风格和使用的框架是其中之一,例如QT 按照惯例广泛使用 getters 和 setters。