唔.. 这大概是 operator 的笔记叭.. 不知道自己为啥要写前半段没用的东西 qwq

# 好像没用的部分

# C++ 运算符

# 运算符与函数

运算符举例:

  • string 类: + 连接字符串。 "Hello" + " Chino!"
  • array/vector 类: [] 访问元素。 v[0] = 233;
  • path 类: / 连接路径元素。 p = p / "C" / "Users" / "Chino";

运算符可以看作函数,不同处:

  • 语法区别,前中后缀什么什么的..
  • 不能定义新运算符。
  • 运算符作用域内置类型的行为不能修改,例如 2 * 3 结果不能是 1。

# 平面向量类

开始重复造轮

  • 数据成员:x, y 或 array<double, 2> v
  • 运算方法:+, -, 数乘,点乘,长度,方向,==, !=, ​<,>, <=, >= ...
  • TDD 测试驱动开发:
    • 编写运行测试代码。
    • 改动,尽快让测试程序可运行。
    • 重构代码,优化设计。
  1. 测试代码:
// 创建对象
Vec2D v1{3, 5}, v2{4, 6};
// 转为字符串输出
cout << "v1 = " << v1.toString() << endl;
cout << "v2 = " << v2.toString() << endl;
// 向量加法
Vec2D v3 = v1.add(v2);
Vec2D v4 = v3.add(10.0);
cout << "v3 = " << v3.toString() << endl;
cout << "v4 = " << v4.toString() << endl;
// 向量减法,点积,数乘
Vec2D v5 = v2.subtract(v1);
double v6 = v2.dot(v1);
Vec2D v7 = v3.multiply(2.1);
cout << "v2 - v1 = " << v5.toString() << endl;
cout << "v2 . v1 = " << v6 << endl;
cout << "v3 * 2.1 = " << v7.toString() << endl;
// 取反
Vec2D v8 = v2.negative();
cout << "-v2 = " << v8.toString() << endl;
// 自增,自减
cout << "++v8 = " << v8.increase().toString() << endl;
cout << "--v2 = " << v2.increase().toString() << endl;
// 读取,修改
cout << "v1.x_ = " << v1.at(0) << endl;
cout << "v1.y_ = " << v1.at(1) << endl;
// 长度与角度
cout << "v1.magnitude = " << v1.magnitude() << endl;
cout << "v1.direction = " << v1.direction() << endl;
// 比较两向量
cout << "v1 ? v2 : " << v1.compareTo(v2) << endl;
  1. 编写平面向量类,实现测试功能。
class Vec2D
{
private:
    double x_, y_;
public:
    Vec2D(double x = 0, double y = 0)
    {
        x_ = x;
        y_ = y;
    }
    ~Vec2D() = default;
    string toString()
    {
        return string("(" + to_string(x_) + ", " + to_string(y_) + ")");
    }
    Vec2D add(Vec2D secondVec2D)
    {
        return Vec2D(this -> x_ + secondVec2D.x_, this -> y_ + secondVec2D.y_);
    }
    Vec2D add(double num)
    {
        return Vec2D(this -> x_ + num, this -> y_ + num);
    }
    Vec2D subtract(Vec2D secondVec2D)
    {
        return Vec2D(this -> x_ - secondVec2D.x_, this -> y_ - secondVec2D.y_);
    }
    Vec2D subtract(double num)
    {
        return Vec2D(this -> x_ - num, this -> y_ - num);
    }
    double dot(Vec2D secondVec2D)
    {
        return x_ * secondVec2D.x_ + y_ * secondVec2D.y_;
    }
    Vec2D multiply(double multiplier)
    {
        return Vec2D(x_ * multiplier, y_ * multiplier);
    }
    Vec2D negative()
    {
        return Vec2D(-x_, -y_);
    }
    Vec2D& increase()
    {
        x_++; y_++;
        return *this;
    }
    Vec2D& decrease()
    {
        x_--; y_--;
        return *this;
    }
    double& at(const int index)
    {
        if (0 ==  index)
            return x_;
        if (1 == index)
            return y_;
        throw out_of_range("at() only accept 0 or 1 as parameter."); // 抛出异常
    }
    double magnitude()
    {
        return sqrt(x_ * x_ + y_ * y_);
    }
    double direction()
    {
        return atan(y_ / x_);
    }
    int compareTo(Vec2D secondVec2D)
    {
        double m1 = this -> magnitude(), m2 = secondVec2D.magnitude();
        if (fabs(m1 - m2) < 1e-10)
            return 0;
        return m1 > m2 ? 1 : -1;
    }
};

# 运算符重载

可重载:

  • 类型转换运算符:double, int, char, ……

  • new/delete, new []/delete[]

  • ""_suffix 用户自定义字面量运算符 (自 C++11 起)

  • 一般运算符。

不可重载:

OperatorName
.类属关系运算符
.*成员指针运算符
::作用域运算符
? :条件运算符
#编译预处理符号

# 运算符函数

v1 < v2 等价于 v1.operator<(v2) ,定义(接上段):

bool Vec2D::operator<(Vec2D & secondVec2D)
{
	return this -> compareTo(secondVec2D) < 0;
}

# 左值、右值、将亡值

左值:指定一个函数或对象,是可以取地址的表达式。

  • 解引用表达式 *p
  • 字符串字面量 "qwq"
  • 前自增 / 自减 ++i
  • 赋值或复合运算符表达式 x = ym *= n

纯右值:不与对象相关联(字面量)或求值结果是字面量的匿名临时对象。

  • 普通字面量: 'a'233
  • 返回非引用的函数调用 int f() { return 1; }
  • 后自增 / 自减 i++
  • 算数 / 逻辑 / 关系表达式 / 取地址 a + b a < b a != b &a

将亡值:将纯右值转化为右值引用的表达式。(傻...owo


# 大概有用的部分

语法: 返回类型 operator 运算符(参数) { 函数体 }

# 算术 + - * /

  • 返回值一般是右值。
  • 运算符函数的参数类型可以是引用,最好用 const 修饰。

实例:

class Vec2D
{
private:
    double x_, y_;
public:
    Vec2D(double x = 0, double y = 0)
    {
        x_ = x;
        y_ = y;
    }
    ~Vec2D() = default;
    string toString()
    {
        return string("(" + to_string(x_) + ", " + to_string(y_) + ")");
    }
    Vec2D operator +(const Vec2D &secondVec2D)
    {
        return vec2D(x_ + secondVec2D.x_, y_ + secondVec2D.y_);
    }
    // 不能 double::operator+(Vec2D),只能友元
    friend Vec2D operator *(const double&, const Vec2D&);
};
Vec2D operator *(const double& num, const Vec2D& vec)
{
    return Vec2D(num * vec.x_, num * vec.y_);
}
int main()
{
    Vec2D v1{3, 5}, v2{4, 6};
    // 向量加法,乘法
    Vec2D v3 = v1 + v2;
    Vec2D v4 = 2.0 * v1;
    cout << "v3 = " << v3.toString() << endl;
    cout << "v4 = " << v4.toString() << endl;
    return 0;
}

# 赋值 += -= *= /= =

# += -= *= /=

  • 采用 this 改变自身值。

  • operator 返回值类型一般写成引用。

实例:(接上段)

public:
// 这里不加 & amp; 的话,像 (v1 += v2) += v2; 之类的操作会炸掉 qwq
	Vec2D& operator += (const Vec2D &secondVec2D)
    {
        *this = this -> add(secondVec2D);
        return *this;
    }
int main()
{
    Vec2D v1{3, 5}, v2{4, 6};
    v1 += v2;
    cout << "v1 = " << v1.toString() << endl; // 7, 11
   	return 0;
}

# =

  • 默认进行一对一浅拷贝。
  • 需要深拷贝时,重载赋值 = 运算符。

# 比较 > == < >= <= !=

  • 重载 < 常用于 STL 里的各种操作。
  • 使用友元。

# 下标访问 [ ]

并没有什么意料之外的:

class Vec2D
{
private:
    double x_, y_;
public:
    double& operator [] (const int &index)
    {
        if (index == 0)
            return x_;
        if (index == 1)
            return y_;
        else
            throw out_of_range("at() only accept 0 or 1 as parameter.");
    }
};
int main()
{
    Vec2D v1{3, 5};
    v1[0] += 1;
    cout << "v1.x_ = " << v1[0] << endl; // 4
    return 0;
}
  • 假设 @为某单目运算符,编译器遇到 @obj 时, 是否传参取决于 operator @ () 是成员函数 operator @ () 还是友元函数 operator @ (Type &) //可能需要引用

# -

Vec2D Vec2D::operator - ()
{
	return Vec2D(-x_, -y_); // 临时匿名对象
}

# 自增 / 自减 ++/--

  • 前缀返回值为左值

  • 后缀返回值为右值

运算符类内定义类外定义
++aT& T::operator ++ ();T& operator ++ (T& a);
a++T T::operator ++ (int dummy);T T::operator ++ (T& a, int dummy);

dummy 占位符,用于区分前置与后置,调用时并不会传递参数。

实例:

class Vec2D
{
private:
    double x_, y_;
public:
    Vec2D(double x = 0, double y = 0)
    {
        x_ = x;
        y_ = y;
    }
    ~Vec2D() = default;
    string toString()
    {
        return string("(" + to_string(x_) + ", " + to_string(y_) + ")");
    }
    Vec2D& operator ++()
    {
        ++x_; ++y_;
        return *this;
    }
    Vec2D operator ++(int dummy)
    {
        Vec2D tmp = Vec2D(x_, y_);
        x_++; y_++;
        return tmp;
    }
};
int main()
{
    Vec2D v1{3, 5};
    cout << "v1++ = " << v1++.toString() << endl; // 3, 5
    cout << "++v1 = " << (++v1).toString() << endl; // 5, 7
    (++v1)++;
    cout << "v1 = " << v1.toString() << endl; // 7, 9
    return 0;
}

# 流插入 / 提取运算符 >>/<<

  • 是二元运算符,第一个操作数是 cin 或 cout
  • 因为要把自定义对象作为第二个操作数~~(不会吧不会吧不会真的有人想把代码写得像💩一样难看吧)~~,所以只采用友元。

实例:

#include <iostream>
using namespace std;
class Vec2D
{
private:
    double x_, y_;
public:
    Vec2D(double x = 0, double y = 0)
    {
        x_ = x;
        y_ = y;
    }
    ~Vec2D() = default;
    friend ostream& operator << (ostream&, const Vec2D&);
    friend istream& operator >> (istream&, Vec2D&);
};
ostream& operator << (ostream &os, const Vec2D& v) // 返回 ostream& 以连续使用流插入运算符
{
    return os << "(" << v.x_ << ", " << v.y_ << ")";
}
istream& operator >> (istream &is, Vec2D& v) // 别带 const
{
    return is >> v.x_ >> v.y_;
}
int main()
{
    Vec2D v1, v2;
    cin >> v1 >> v2; // 1 2 3 4
    cout << v1 << " qwq " << v2 << endl; // (1, 2) qwq (3, 4)
    return 0;
}

# 对象转换 static_cast<Type>()

  • 语法 operator Type() { return value; }

  • 没有返回值类型。(ctor, dtor 也没有)

  • 包括隐式类型转换与强制类型转换。

# ex

  • 不允许操作基础数据类型,参数至少应有一个自定义类的对象。
  • 以友元函数重载,可以更灵活地指定次序。(部分运算符如 [ ] 不能以友元重载)
更新于