C++ (C+;+;)如果我在类中声明了私有的东西,但可以通过类的公共方法更改它,那么为什么我要将它声明为私有的呢?

C++ (C+;+;)如果我在类中声明了私有的东西,但可以通过类的公共方法更改它,那么为什么我要将它声明为私有的呢?,c++,C++,我创建了一个新的类分数,因为输入分子和分母是常识。我的前辈建议我私下申报分子和分母。但是,如果它们可以被更改,并且无论如何都可能发生数据滥用,那么我为什么要将它们声明为私有呢 分数类的我的代码(如果您想参考我的代码): #ifndef分数 #定义分数 #endif//分数 #包括 #包括 使用名称空间std; 类分数{ 整数; 无效将“”更改为“”形式(); void获取字符串()中的值; 公众: 分数(int,int); 分数(){numer=0;denom=0;} void display(

我创建了一个新的类分数,因为输入分子和分母是常识。我的前辈建议我私下申报分子和分母。但是,如果它们可以被更改,并且无论如何都可能发生数据滥用,那么我为什么要将它们声明为私有呢

分数类的我的代码(如果您想参考我的代码):

#ifndef分数
#定义分数
#endif//分数
#包括
#包括
使用名称空间std;
类分数{
整数;
无效将“”更改为“”形式();
void获取字符串()中的值;
公众:
分数(int,int);
分数(){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完成所有工作();
内联bool操作符get\u float\u num()/this->get\u float\u denom()(分数和rhs){if(float(this->get\u float\u num()/this->get\u float\u denom())>float(rhs.get\u float\u num()/rhs.get\u float\u denom())返回true;否则返回false;}
内联bool操作符get_float_num()/this->get_float_denom())=(分数和rhs){if(float(this->get_float_num()/this->get_float_denom())>=float(rhs.get_float_num()/rhs.get_float_denom())返回true;否则返回false;}
内联布尔运算符==(分数和rhs){if(float(this->get_float_num()/this->get_float_denom())==float(rhs.get_float_num()/rhs.get_float_denom())返回true;否则返回false;}
内联void运算符++(int){numer+=denom;}
内联void运算符+=(int a){numer+=(denom*a);}
内联无效运算符--(int){numer-=denom;}
内联无效运算符-=(int a){numer-=(denom*a);}
内联void运算符=(字符串a){bool denom_not_one=true;int i=0;numer=0;denom=0;for(i=0;a[i]!='/';++i){if(a[i]='\0'){denom=1;denom_not_one=false;break}if(int(a[i])>=48&&int(a[i])=48&&int(a[i])numer=rhs.get_num this->
内联分数运算符*(分数和rhs){分数tmp(this->numer*rhs.get_num(),this->denom*rhs.get_denom());返回tmp;}
内联void操作符*=(分数和rhs){this->numer*=rhs.get_num();this->denom*=rhs.get_denom();}
内联void操作符/=(分数和rhs){this->numer*=rhs.get_denom();this->denom*=rhs.get_num();}
};
空隙率::完成它{
将_更改为_最简单形式();
}
分数:分数(整数a,整数b){
denom=b;
数值=a;
//显示();
}
空隙率::更改为最简单的形式(){
整数除数=1;
bool islessthanzero=false;

如果(numer事实上,使成员
私有化
和使成员
公共化
getter和setter会破坏封装,那么从设计的角度来看,这一切都是一样的


唯一的优点是能够在getter和setter中设置断点,这有助于调试。

这是私有数据-公共接口的思想和原理,用于更改任何私有字段的公共方法具有适当的防御措施,防止将私有字段更改为unw程序中的预期值(即,避免任何。如果该字段只是
公共的
,那么就不会有这样的防御措施。

这与封装有关。如果您只使用基本的setter来操作它,这可能看起来是浪费时间,因此您的问题是,如果您仍然可以修改它,为什么还要将其设为私有。然而,随着您的代码变得越来越复杂,您需要将有其他方法根据业务逻辑修改私有变量

以私有变量weeklyEmployeePay为例,您可以编写一个名为calculateWeeklyEmployeePay(双倍小时,双倍费率)的公共方法。然后,此公共方法将根据方法中的逻辑和给定参数更改私有变量


封装是面向对象编程的一个关键组件。

为了防止数据滥用。当您编写的方法提供了对它们的唯一访问权限时,您的方法的编写方式可以防止私有变量获得错误的值。如果调用方试图设置不适当的值,您可以o各种事情,包括:
-引发异常
-将值钳制到合理的范围
-显示警报。这取决于您。

因此,尽管调用方可以向公共方法发送不适当的值,但您可以选择做些什么。

隔离更改(从实现中)


对于您的情况,如果您想将分子和分母的类型从
int
更改为
float
,如果它们在没有getter的情况下是公共的,则所有客户端也需要更改它们的代码。如果它们是public getter的私有客户端,则客户端不需要更改,因为接口没有更改。这使您可以更灵活地更改i实施细节。

你可以让你的教授参考这个答案

在许多情况下,如果类只是离散值的方便占位符,那么将数据作为接口是合适的

这方面的一个例子是
std::pair
,它具有公共数据成员
first
second
。完全可以在不引用另一个的情况下修改其中一个,因此将代码与
get_first()
set_first()
(请注意,自由函数
auto&std::get(t)
auto&std::get(t)
模拟了这种行为,但有一个特定的原因-它们使通用编程更容易)

另一种情况是,当数据成员是
const
时,数据接口就更合适了。由于是const,它无法更改,因此不需要get/set(它也是线程安全的,但这是另一种情况)

因此,您可以将分数实现为:

struct frac
{
  double numerator, denominator;
};
并允许对argum进行更改
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 };
}