分类目录归档:未分类

类模版

#include 
using namespace std;

template 
class Pair{
    public:
    T1 key;
    T2 value;
    Pair(T1 k, T2 v): key(k), value(v){};
    bool operator < (const Pair & p)const;
};
template 
bool Pair::operator < (const Pair & p) const{
    return key < p.key;
}

int main()
{
    Pair student("Tom", 19);
// 编译器由类模板生成类的过程叫类模板的实例化
// -编译器自动用具体的数据类型
// -替换类模板中的类型参数, 生成模板类的代码
// 由类模板实例化得到的类叫模板类
// -为类型参数指定的数据类型不同, 得到的模板类不同
    Pair score("Tim", 98.5);

赋值运算符的重载

赋值运算符的重载

赋值运算符 ‘=’ 重载

  • 赋值运算符 两边的类型 可以 不匹配

    • 把一个 int类型变量 赋值给一个 Complex对象
    • 把一个 char * 类型的字符串 赋值给一个 字符串对象
  • 需要 重载赋值运算符 ‘=’
  • 赋值运算符 “=” 只能重载为 成员函数

编写一个长度可变的字符串类String

  • 包含一个char * 类型的成员变量

    • 指向动态分配的存储空间
  • 该存储空间用于存放 ‘0’ 结尾的字符串
string s = "hello"; // =是初始化语句
string s;
s = "hello"; //赋值语句

s1 = s2:拷贝

  • 浅拷贝 : 复制地址给s1的str,缺点是共用一块内存不安全
  • 深拷贝 : 分别用不同的内存
 //在 class MyString 里添加成员函数 :
String & operator=(const String &s)
{
    if (str)
        delete[] str;
    str = new char[strlen(s.str) + 1];
    strcpy(str, s.str);
    return *this;
}

以上代码在执行自己赋值给自己的时候出问题

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;
}

对 operator = 返回值类型的讨论

void好不好?

考虑: a = b = c; 等价于a.operator=(b.operator=(c));

String 好不好?
为什么是 String &
运算符重载时, 好的风格 — 尽量保留运算符原本的特性
考虑: (a=b)=c; //会修改a的值
分别等价于:
(a.operator=(b)).operator=(c);

运算符重载的基本概念

运算符

C++预定义表示对数据的运算

  • +, -, *, /, %, ^, &, ~, !, |, =, , != ……
  • 只能用于基本的数据类型
  • 整型, 实型, 字符型, 逻辑型……

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

C++提供了数据抽象的手段:
用户自己定义数据类型 — 类

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

运算符重载

对抽象数据类型也能够直接使用C++提供的运算符

  • 程序更简洁
  • 代码更容易理解
    例如:
  • complex_a和complex_b是两个复数对象
  • 求两个复数的和, 希望能直接写:
    complex_a + complex_b
  • 对已有的运算符赋予多重的含义
  • 使同一运算符作用于不同类型的数据时 有 不同类型的行为
    目的
  • 扩展C++中提供的运算符的适用范围, 以用于类所表示的抽象
    数据类型

同一个运算符, 对不同类型的操作数, 所发生的行为不同

  • (5,10i) + (4,8i) = (9,18i)
  • 5 + 4 = 9

运算符重载的实质是函数重载

返回值类型 operator 运算符(形参表)
{
……
}  

在程序编译时:

  • 把含运算符的表达式–>对 运算符函数 的调用
  • 把 运算符的操作数 –> 运算符函数的 参数
  • 运算符被多次重载时, 根据 实参的类型 决定调用哪个运算
    符函数
  • 运算符可以被重载成普通函数
  • 也可以被重载成类的成员函数

运算符重载为普通函数

Complex operator+ (const Complex & a, const Complex & b)
{
return Complex( a.real+b.real, a.imaginary+b.imaginary);
}
  • 重载为普通函数时, 参数个数为运算符目数

运算符重载为成员函数

只需要一个参数

class Complexs
{
  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;
  x = y - z;
  return 0;
}