跳转到内容

重载`-`和`--`运算符

-既可以是一元运算符(如-5),也可以是二元运算符(如5 - 3),重载时怎样区分要重载的是哪一种?

--既可以是前缀运算符(--i),也可以是后缀运算符(i--),重载时怎样区分要重载的是哪一种?

编译器根据参数的数量推断要重载的是一元运算符还是二元运算符。

  • 在类外重载时,如果有两个参数,那么重载二元运算符。左操作数是第一个参数;右操作数是第二个参数。
  • 在类内重载时,如果有一个参数,那么重载二元运算符。左操作数是当前对象;右操作数是参数。
  • 在类外重载时,如果有一个参数,那么重载一元运算符。操作数是函数参数。
  • 在类内重载时,如果没有参数,那么重载一元运算符。操作数是当前对象。

编译器这样来区分重载的是前缀运算符还是后缀运算符:

  • 前缀运算符的重载不带参数,
  • 后缀运算符的重载带一个未使用的int类型参数。

例子:vector 的包装器,在上面添加了-一元和二元运算符,以及--前缀和后缀运算符

关键代码:

// 重载一元运算符`-`,返回一个新对象,其中所有元素为原对象的相反数。
MyVector<T> operator-() const {
auto result{*this};
std::transform(result.m_values.begin(), result.m_values.end(), result.m_values.begin(), [](const auto& val){return -val;});
return result;
}
// 重载二元运算符`-`,返回一个新对象,其中的元素是两个对象内各个元素对应相减的结果。
MyVector<T> operator-(const MyVector<T>& rhs) const {
size_t minN {std::min(m_values.size(), rhs.m_values.size())};
std::vector<T> temp(minN);
for (size_t i{0}; i < minN; ++i) {
temp[i] = m_values[i] - rhs.m_values[i];
}
return MyVector{std::move(temp)};
}
// 重载前缀一元运算符`--`
MyVector<T>& operator--() {
std::transform(this->m_values.begin(), this->m_values.end(), this->m_values.begin(), [](auto& val){return --val;});
return *this;
}
// 重载后缀一元运算符`--`
MyVector<T> operator--(int) {
auto result{*this};
--*this;
return result;
}

完整类定义和实现:

/*
* vector 的包装器,在 vector 上添加了`-`一元和二元运算符,以及`--`前缀和后缀运算符
* */
#include <vector>
#include <algorithm>
#include <iterator>
#include <iostream>
// 确保所有元素都具有相同的类型
template<typename T, typename... Args>
concept SameType = (std::same_as<T, Args> && ...);
template <typename T>
class MyVector {
public:
template <SameType<T>... Tn>
explicit MyVector(const T& arg, const Tn&... args) : m_values{} {
m_values.push_back(arg);
(m_values.push_back(args), ...);
}
explicit MyVector(std::vector<T> values) : m_values{std::move(values)} {}
void print() const {
std::copy(m_values.begin(), m_values.end(), std::ostream_iterator<T>(std::cout, " "));
std::cout << std::endl;
}
// 重载一元运算符`-`,返回一个新对象,其中所有元素为原对象的相反数。
MyVector<T> operator-() const {
auto result{*this};
std::transform(result.m_values.begin(), result.m_values.end(), result.m_values.begin(), [](const auto& val){return -val;});
return result;
}
// 重载二元运算符`-`,返回一个新对象,其中的元素是两个对象内各个元素对应相减的结果。
MyVector<T> operator-(const MyVector<T>& rhs) const {
size_t minN {std::min(m_values.size(), rhs.m_values.size())};
std::vector<T> temp(minN);
for (size_t i{0}; i < minN; ++i) {
temp[i] = m_values[i] - rhs.m_values[i];
}
return MyVector{std::move(temp)};
}
// 重载前缀一元运算符`--`
MyVector<T>& operator--() {
std::transform(this->m_values.begin(), this->m_values.end(), this->m_values.begin(), [](auto& val){return --val;});
return *this;
}
// 重载后缀一元运算符`--`
MyVector<T> operator--(int) {
auto result{*this};
--*this;
return result;
}
private:
std::vector<T> m_values;
};

测试:

int main() {
MyVector values{1,2,3};
values.print();
auto values2 {-values}; // -1 -2 -3
values2.print();
auto values3{values - values2}; // 2 4 6
values3.print();
--values3; // 1 3 5
values3.print();
auto values4{values3--}; // values4: 1 3 5, values3: 0 2 4
values4.print();
values3.print();
}