设为首页 加入收藏

TOP

PKU C++程序设计实习 学习笔记4 运算符重载(一)
2015-11-21 01:01:04 来源: 作者: 【 】 浏览:3
Tags:PKU 程序设计 实习 学习 笔记 运算 重载

第四章 运算符重载

4.1 运算符重载的基本概念

1. 运算符


2. 自定义数据类型与运算符重载

C++提供了数据抽象的手段:用户自己定义数据类型 -- 类
? 调用类的成员函数—>操作它的对象

类的成员函数—>操作对象时,很不方便
? 在数学上,两个复数可以直接进行+/-等运算 Vs. 在C++中,直接将+或-用于复数是不允许的

3. 运算符重载

对抽象数据类型也能够直接使用C++提供的运算符
? 程序更简洁
? 代码更容易理解运算符重载
? 对已有的运算符赋予多重的含义
? 使同一运算符作用于不同类型的数据时—>不同类型的行为目的
? 扩展C++中提供的运算符的适用范围,以用于类所表示的抽象数据类型同一个运算符,对不同类型的操作数,所发生的行为不同
? (5,10i) + (4,8i) = (9,18i)
? 5 + 4 = 9运算符重载的实质是函数重载
返回值类型 operator 运算符(形参表)
{
……
}
在程序编译时:
? 把含 运算符的表达式 —> 对 运算符函数 的调用
? 把 运算符的操作数 —> 运算符函数的 参数
? 运算符被多次重载时, 根据 实参的类型 决定调用哪个运算符函数
? 运算符可以被重载成普通函数
? 也可以被重载成类的成员函数

4. 运算符重载为普通函数

class Complex {
  public:
    Complex( double r = 0.0, double i= 0.0 ){
      real = r;
      imaginary = i;
    }
  double real; // real part
  double imaginary; // imaginary part
};

Complex operator+ (const Complex & a, const Complex & b)
{
  return Complex( a.real+b.real, a.imaginary+b.imaginary);
} // “类名(参数表)” 就代表一个对象

Complex a(1,2), b(2,3), c;
c = a + b;// 相当于什么?  operator+(a,b)
重载为普通函数时,参数个数为运算符目数

5. 运算符重载为成员函数

class Complex {
  public:
    Complex( double r= 0.0, double m = 0.0 ):real(r), imaginary(m) { } // constructor
    Complex operator+ ( const Complex & ); // addition
    Complex operator- ( const Complex & ); // subtraction
  private:
    double real; // real part
    double imaginary; // imaginary part
};
// Overloaded addition operator
Complex Complex::operator+(const Complex & operand2) {
  return Complex( real + operand2.real,imaginary + operand2.imaginary );
}
// Overloaded subtraction operator
Complex Complex::operator- (const Complex & operand2){
  return Complex( real - operand2.real,imaginary - operand2.imaginary );
}
int main(){
?Complex x, y(4.3, 8.2), z(3.3, 1.1);
?x = y + z;// 相当于什么?  y.operator+(z)
?x = y - z;// 相当于什么?  y.operator-(z)
?return 0;
}
重载为成员函数时,参数个数为运算符目数减一

4.2 赋值运算符的重载

1. 赋值运算符 ‘=’ 重载

赋值运算符 两边的类型 可以 不匹配
? 把一个 int类型变量 赋值给一个 Complex对象
? 把一个 char * 类型的字符串 赋值给一个 字符串对象

需要 重载赋值运算符 ‘=’

赋值运算符 “=” 只能重载为 成员函数

编写一个长度可变的字符串类String
? 包含一个char * 类型的成员变量
—> 指向动态分配的存储空间
? 该存储空间用于存放 ‘\0’ 结尾的字符串

class String {
  private:
    char * str;
  public:
    String () : str(NULL) { } //构造函数, 初始化str为NULL
    const char * c_str() { return str; } //返回值为const类型,保证str不会被修改。比如char* p=str.c_str();则编译器会报错,类型不匹配。
    char * operator = (const char * s);
    ~String( );//需要考虑String对象是否指向了动态分配的存储空间
}; 
//重载‘=’使得obj = “hello”能够成立
char * String::operator = (const char * s){
  if(str) delete [] str;
  if(s) { //s不为NULL才会执行拷贝
    str = new char[strlen(s)+1];
    strcpy(str, s);
  }
  else
    str = NULL;
  return str;
}
String::~String( ) {
  if(str) delete [] str;
};
int main(){
  String s;
  s = “Good Luck,” ;
  cout << s.c_str() << endl;
  // String s2 = “hello!”; //这条语句要是不注释掉就会出错
  s = "Shenzhou 8!";
  cout << s.c_str() << endl;
  return 0;
}

2. 重载赋值运算符的意义 – 浅复制和深复制

S1 = S2;

?

浅复制/浅拷贝
执行逐个字节的复制工作

?

\
\

S1和S2指向了同一块动态分配内存区域,那么当S1和S2同时消亡的时候,这一块内存空间就会被先后释放两次。这样就会导致严重的内存错误,甚至可能引发程序意外的中止。
所以我们看到,这样的一个浅拷贝,或者浅复制的工作本身并不能实现我们所希望实现的像S2中间的这个str字串复制给S1本身指向的那一块空间。

?

深复制/深拷贝
将一个对象中指针变量指向的内容 —> 复制到另一个对象中指针成员对象指向的地方

?

\

\

在 class MyString 里添加成员函数:

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

?

3. 思考

?

考虑下面语句,是否会有问题?
MyString s; s = “Hello”; s = s;

正确写法:

String & String::operator = (const String & s){
  if(str == s.str) return * this;//增加此行
  if(str) delete [] str;
  if(s.str) { //s.str不为NULL才会执行拷贝
    str = new char[strlen(s.str)+1];
    strcpy( str,s.str);
  }
  else
    str = NULL;
  return * this;
}

?

4. 对 operator = 返回值类型的讨论

v
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇poj2728--Desert King(最优比率.. 下一篇[ACMcoder] A + B Problem II

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: