(C++)如果我在类中声明了一些私有的东西,但它可以通过类的公共方法进行更改,那么我为什么要声明它为私有的呢
(C++ )If I declare something private in a class but it can be changed via public methods of class, then why should I declare it private?
我创建了一个新的类分数,因为输入分子和分母是常识。学长建议我私下申报分子和分母。但是,如果它们可以更改,并且无论如何都可能发生数据滥用,那么我为什么要宣布它们为私有?
我的分数类代码(如果你想参考我的代码):
#ifndef FRACTION_H
#define FRACTION_H
#endif // FRACTION_H
#include<string>
#include<iostream>
using namespace std;
class fraction{
int numer, denom;
void change_to_simplest_form();
void get_value_in_string();
public:
fraction(int,int);
fraction(){numer =0; denom =0;}
void display();
int get_num(){return numer;}
int get_denom(){return denom;}
float get_float_num(){return float(numer);}
float get_float_denom(){return float(denom);}
void get_it_all_done();
inline bool operator<(fraction &rhs){if(float(this->get_float_num()/this->get_float_denom())<float(rhs.get_float_num()/rhs.get_float_denom()))return true; else return false;}
inline bool operator>(fraction &rhs){if(float(this->get_float_num()/this->get_float_denom())>float(rhs.get_float_num()/rhs.get_float_denom()))return true; else return false;}
inline bool operator<=(fraction &rhs){if(float(this->get_float_num()/this->get_float_denom())<=float(rhs.get_float_num()/rhs.get_float_denom()))return true; else return false;}
inline bool operator>=(fraction &rhs){if(float(this->get_float_num()/this->get_float_denom())>=float(rhs.get_float_num()/rhs.get_float_denom()))return true; else return false;}
inline bool operator==(fraction &rhs){if(float(this->get_float_num()/this->get_float_denom())==float(rhs.get_float_num()/rhs.get_float_denom()))return true; else return false;}
inline void operator++(int){numer+=denom;}
inline void operator+=(int a){numer+=(denom*a);}
inline void operator--(int){numer-=denom;}
inline void operator-=(int a){numer-=(denom*a);}
inline void operator=(string a){bool denom_not_one = true;int i =0;numer=0;denom=0;for(i =0;a[i]!='/';++i){if(a[i]==' '){denom=1;denom_not_one=false;break;}if(int(a[i])>=48 && int(a[i])<=57){numer*=10;if(a[i]!='0'){numer+=(int(a[i]-48));}}}for(;a[i]!=' ' && denom_not_one;++i){if(int(a[i])>=48 && int(a[i])<=57){denom*=10;if(a[i]!='0'){denom+=(int(a[i]-48));}}}}
inline void operator=(fraction &rhs){this->numer=rhs.get_num();this->denom=rhs.get_denom();}
inline fraction operator*(fraction &rhs){fraction tmp(this->numer*rhs.get_num(),this->denom*rhs.get_denom()); return tmp;}
inline void operator*=(fraction &rhs){this->numer*=rhs.get_num();this->denom*=rhs.get_denom();}
inline void operator/=(fraction &rhs){this->numer*=rhs.get_denom();this->denom*=rhs.get_num();}
};
void fraction:: get_it_all_done(){
change_to_simplest_form();
}
fraction::fraction(int a, int b){
denom = b;
numer =a;
// display();
}
void fraction::change_to_simplest_form(){
int divisor = 1;
bool islessthanzero = false;
if(numer<0){
numer*=(-1);
islessthanzero = true;
}
while(divisor <= numer && divisor <= denom){
if(numer%divisor==0){
if(denom%divisor==0){
numer/=divisor;
denom/=divisor;
}
}
divisor++;
}
if(islessthanzero){numer*=(-1);}
}
void fraction::display(){
change_to_simplest_form();
cout << "(" << numer << "/" << denom << ")" ;
}
std::ostream &operator<<(std::ostream &os,fraction &m){
m.get_it_all_done();
if(m.get_denom()!=1){
cout << "(" << m.get_num() << "/" << m.get_denom() << ")" ;
}
else cout << m.get_num();
return os;
}
这是私有数据-公共接口的思想和原理,用于更改任何私有字段的公共方法具有适当的防御措施,可以防止将程序中的私有字段更改为不需要的值(即避免破坏任何不变量)。如果场地只是public
,那么就不会有这样的防御。
事实上,让成员private
和拥有public
getter和setter会破坏封装,所以从设计的角度来看,这一切都是一样的。
唯一的优点是能够在getter和setter中设置断点,这在调试过程中会有所帮助。
隔离更改(与实现)。
对于您的情况,如果您想将分子和分母的类型从int
更改为float
,如果它们是公共的而没有getter,那么所有客户端也需要更改它们的代码。如果它们与公共getter是私有的,则客户端不需要更改,因为接口不会更改。它使您可以更灵活地更改实现细节。
你可以让你的教授参考这个答案。
在许多情况下,如果类只是离散值的方便占位符,那么数据作为接口是合适的。
这方面的示例是具有公共数据成员first
和second
的std::pair
。修改其中一个而不参考另一个是完全合适的,因此用get_first()
和set_first()
混淆代码是没有意义的(请注意,自由函数auto& std::get<0>(t)
和auto& std::get<1>(t)
模仿了这种行为,但有一个特定的原因-它们使通用编程更容易)。
另一个时间数据是接口更合适的是当数据成员是const
时。由于是const,它不能改变,所以不需要get/set的想法(它也是线程安全的,但那是另一回事)。
这样你就可以实现你的分数:
struct frac
{
double numerator, denominator;
};
并允许更改参数。
但实际上,在分数中,分子和分母并不独立。例如,设置分母为零可能应该尽早(通过抛出异常!),并且您可能希望尽早对分数进行归一化,这取决于您实现分数运算的策略。
因此,这开始变得更加明智:
struct frac
{
frac(double n, double d) : numerator(n), denominator(d) {}
frac& set_denominator(double d)
{
if (d == 0.0) { // probably should check the ratio of n to d here
// but this is a simplified example for exposition
throw std::invalid_argument(std::to_string(d));
}
denominator = d;
normalise();
return *this;
}
void normalise() {
// find gcd etc etc
}
private:
double numerator, denominator;
};
另一种方法是将分数设计为不可变的,并要求任何更改都产生一个副本。
在这种情况下,这是合适的:
struct frac
{
frac(double n, double d) : numerator(n), denominator(d) {}
frac replace_denominator(double d)
{
if (d == 0.0) { // probably should check the ratio of n to d here
// but this is a simplified example for exposition
throw std::invalid_argument(std::to_string(d));
}
return normalised_frac(numerator, d);
}
const double numerator, denominator;
};
frac normalised_frac(double n, double d)
{
// normalisation operations on n and d
return frac { n, d };
}
根据您的要求,每种形式的箱子的强度都会有所不同。在多处理中,通常首选具有不可变的离散副本。这是Haskell和D.等语言的规范
这与封装有关。如果你只使用一个基本的setter来操作它,这似乎是在浪费时间,因此你的问题是,如果你仍然可以修改它,为什么还要将其设为私有。然而,随着你的代码变得越来越复杂,你将有其他方法根据业务逻辑修改私有变量。
例如,以一个私有变量weeklyEmployeePay为例,您可以编写一个名为calculateWeeklyEmperoyeePay(双倍小时,双倍费率)的公共方法。然后,这个公共方法将根据方法中的逻辑和给定的参数来更改私有变量。
封装是面向对象编程的关键组成部分。
为了防止数据滥用。当您编写的方法提供了对它们的唯一访问权限时,可以以防止私有变量获得坏值的方式编写方法。如果调用方试图设置一个不合适的值,您可以执行各种操作,包括:
-引发异常
-将值限制在有意义的范围内
–显示警报。这取决于你
因此,尽管调用者可以向公共方法发送不合适的值,但您可以选择对此进行处理。
- 声明高维向量的更简洁的方法
- 模板方法访问正向声明的类仅在没有此指针的情况下无法编译
- 将子类方法声明为基类的友元
- 如何在声明为 const 的方法中更改类成员
- 编译器无法识别在类声明之外定义的方法
- 在类中声明 Array 成员的正确方法
- 如何在该接收类之外声明嵌套类的方法
- 转发声明在命名空间中不起作用的替代方法
- 在实现文件中使用模板参数声明方法
- 为什么在主方法之前声明方法会产生错误 c++
- 在 cpp 正文中声明方法时未定义的符号
- 声明方法时没有名称空间,也没有对C 作用的方法的对象
- 无法在类中声明方法 (C++_
- 可变声明方法
- 为什么这种前向声明方法会产生错误
- 在c++中可以通过模板声明方法吗?
- 在c++中声明方法时= 0的含义是什么?
- 为什么我需要为部分模板专门化重新声明方法/成员?
- 两种数组声明方法的区别
- 强制编译器声明方法是否已被实现- c++