2.赋值和公有数据

2.赋值和公有数据

    和复制构造函数一样,如果我们没有声明赋值操作符函数,c++会自动为我们合成一个。缺省的赋值操作符的适用场合和缺省的复制构造函数一样,如果缺省的复制构造函数是错误的,那么缺省的赋值操作符几乎也可以被确定为错误的(反之亦然)。

    赋值操作符和复制构造函数都有着几乎同样的逻辑,它们的区别主要在于:

        1.当对象被自赋值时,赋值操作符必须可以工作

        2.每次对赋值操作符的调用都会改写一个已经存在了的值,如果在被改写的对象中使用了对象外的资源,那么我们可能需要释放这些资源

        3.赋值操作符可以向外返回一个值

    如下是String类的复制构造函数和赋值操作符:

String::String(const String& s):data(new char[strlen(s.data)+1])
{
	strcpy(data, s.data);
}
const String& String::operator=(const String& s)
{
	if(&s != this){
		delete [] data;
		data = new char[strlen(s.data)+1];
		strcpy(data, s.data);
	}
	return *this;
}

    值得注意的是上面中的&sthis的比较,如果没有这个比较的话,对于String的自赋值,我们会先删除String中的数据,然后又试图对这些刚被删除的数据进行拷贝,明显是不行的。还有一个值得注意的是:一旦我们确信正在处理两个不同的对象,赋值操作符必须将原有值所控制的资源释放掉(代码中delete的作用)。如果他们中有一个共有逻辑,我们通常会提取出来放到一个私用的成员函数中,并在复制构造函数和赋值操作符中去调用这个共有逻辑。

2.1关于operator=的返回值

    赋值操作符应该返回一个被赋值对象的常量引用。这使得用户可以写出如下的代码:

Complex x,y;

x=y=Complex(0,0);

    被重载的操作符和内建的操作符有同样的优先级和结合顺序,=是右结合的。在实际中,即使我们没有使用到返回值,通常也会让赋值操作符返回一个值,这在大部分情况下,对性能不会带来什么影响。

3.公用数据

如下一个复数类:

  class Complex
  {
  public:
  double real_d;
  	double imag_d;
  	Complex(double r, double i):real_d(r), imag_d(i){}
  };

这个类可能可以正常工作,但有着非常大的缺陷,问题就是那两个公有的数据成员,可以被用户任意修改!

所以我们在一开始就应该避免使用这样的公用数据,如下:

  class Complex
  {
  private:
  	double real_d;
  	double imag_d;
  public:
  	Complex(double r, double i):real_d(r), imag_d(i){}
  	double real() const {return real_d;}
  	double imag() const {return imag_d;}
  	void real(double r) {real_d = r;}
  	void imag(double i) {imag_d = i;}
  };

3.1表示不变量

公用数据还会使我们的类很难用来保证表示不变量。如一个有理数的类Rational

  class Rational
  {
  private:
  	int num_d;
  	int denom_d;
  public:
  	Rational(int n, int d);
  	int num() const {return num_d;}
  	int denom() const {return denom_d;}
  	void num(int n) {num_d = n;}
  	void denom(int);
  };
  static void check_zero(int d)
  {
  	if(d == 0){
  		cerr << "zero denominator in Rational\n";
  		abort();
  	}
  }
  Rational::Rational(int n, int d):num_d(n),denom_d(d)
  {
  	check_zero(d);
  }
  void Rational::denom_d(int d)
  {
  	check_zero(d);
  	denom_d = d;
  }

如上,我们在Rational的其它成员函数中,我们就不必担心分母出现0的情况,就能保证不变量的成立。得出结论:避免公用数据成员的出现。公用成员将是得我们很难去更改类的实现(如改变信息的存储格式或存储位置);它也无法保证表示不变量的长期有效性。






你可能感兴趣的:(C++高级惯用法,C++赋值,公有数据)