3 Operator Overloading¶
Basic Concepts¶
Allows user-defined types to act like built-in types
以下运算符都可以被重载
+ - * / % ^ & | ~
= < > += -= *= /= %=
^= &= |= << >> >>= <<= ==
!= <= >= ! && || ++ --
, ->* -> () []
new new[]
delete delete[]
以下运算符不可以被重载
只有存在的运算符可以被重载
- 像
**
这样的运算符不可以被重载
被重载的运算符必须符合之前运算符的算子个数并保留之前的优先级
重载运算符的两种方式:
-
重载运算符可以在类里面作为成员函数进行重载,会有一个隐式的参数
-
重载运算符也可以作为全局函数被重载
Member Function
-
Implicit first argument
-
Full access to the class definition and all fields
-
No type conversion performed on receiver
对于第三点的意思是接收者不可以做类型转换
对于二元运算符,相应的重载函数需要一个参数,而对于单元运算符,相应的函数不需要参数
Global operators
-
Explicit first argument
-
Does not need special access to classes
-
May need to be a friend
-
Type conversions performed on both arguments
一般来说作为全局函数的运算符重载都会作为某一个类的友元函数
class Integer {
public:
friend Integer operator+(const Integer&,
const Integer&);
...
private:
int i;
};
Integer operator+(const Integer& lhs, const Integer& rhs)
{
return Integer( lhs.i + rhs.i );
}
与之前不同的是,对于两个算子我们都可以做隐式转换
z = x + y; // operator+(x, y)
z = x + 3; // operator+(x, Integer(3))
z = 3 + y; // operator+(Integer(3), y)
z = 3 + 7; // Integer(10)
Argument passing
Pass it as a const reference if it is read-only (except built-ins).
Make member functions const if they do not change the class (relational operators, + , - , etc.).
确认参数是只读的,那么加上 const;对于那些不会改变类中数据的,函数也设置为 const
Return values
返回值的设置与运算符紧密相关,比如说 operator+
返回的就是一个新的对象,逻辑运算符返回的就是 bool
值
下面是一些运算符重载的函数签名
-
+-*/%^&|~:
T operator X(const T& l, const T& r)
-
! && || < <= == >= >:
bool operator X(const T& l, const T& r)
-
[]:
E& T::operator [](int index)
Operators ++
and --
¶
如何区分前缀表达式与后缀表达式?
class Integer {
public:
...
Integer& operator++(); //prefix++
Integer operator++(int); //postfix++
Integer& operator--(); //prefix--
Integer operator--(int); //postfix--
...
};
对于后缀表达式需要一个 int
参数,然后编译器会自己给他赋值为0
Integer x(5);
++x; // calls x.operator++();
x++; // calls x.operator++(0);
--x; // calls x.operator--();
x--; // calls x.operator--(0);
相应的实现方式如下
Integer& Integer::operator++() {
this->i += 1; // increment
return *this; // fetch
}
// the int argument is not used so leave it unnamed
Integer Integer::operator++( int ){
Integer old( *this ); // fetch
++(*this); // increment
return old; // return
}
注意前缀表达式返回的是一个引用,而后缀表达式返回的是一个对象。同时我们也可以发现后缀是由前缀实现的,因为这两者是相关的。
像这样相关的运算符都可以通过这样的实现方式,因为这样可以保证关联性,方便代码的维护
class Integer {
public:
bool operator==( const Integer& rhs ) const;
bool operator!=( const Integer& rhs ) const;
bool operator<( const Integer& rhs ) const;
bool operator>( const Integer& rhs ) const;
bool operator<=( const Integer& rhs ) const;
bool operator>=( const Integer& rhs ) const;
}
implement !=
in terms of ==
bool Integer::operator==( const Integer& rhs ) const {
return i == rhs.i;
}
bool Integer::operator!=( const Integer& rhs ) const {
return !(*this == rhs);
}
Operator []
and ()
¶
Operator []
- Must be a member function
- Single argument
- Implies that the object acts like an array, should return a reference
// 重载 [] 运算符用于常量对象(只读)
int operator[](int index) const {
if (index >= size || index < 0) {
throw out_of_range("Index out of bounds");
}
return data[index];
}
Operator ()
A functor, which overloads the function call operator, is an object that acts like a function.
struct F {
void operator()(int x) const {
std::cout << x << "\n";
}
}; // F is a functor class
F f; // f is a functor
f(2); // calls f.operator()
User-defined type conversions¶
Compilers perform implicit conversions using:
-
single-argument constructors 单参数的构造函数
-
type conversion operators 类型转换运算符
Single argument constructors¶
class PathName {
string name;
public:
PathName(const string&);
~ PathName();
};
...
string abc("abc");
PathName xyz(abc); // OK!
xyz = abc; // OK abc => PathName
可以直接用 string
给 PathName
类型初始化,会进行一个隐式的转化。我们也可以在 PathName(const string&);
前面加上 emplicit
使得这样的隐式转换是禁用的
Conversion operator¶
class Rational {
public:
operator double() const {
return numerator / (double)denominator;
}
}
Rational r(1,3);
double d = 1.3 * r; // r => double
-
The function will be called automatically
-
Return type is same as the function name
这样的转换运算符一般格式为 X::operator T()
-
Operator name is any type descriptor
-
No explicit arguments
-
No return type
A conversion operator can be used to convert an object of one class into an object of
-
another class
-
a built-in type
Summary¶
Built-in conversions, e.g.,
-
char
=>short
=>int
=>float
=>double
-
T[]
=>T*
User-defined type conversions T
=> C
if
- either
C(T)
is a valid constructor call forC
这个是在 C 中定义,所以如果 C 为内置类型,那么这种方法就不可以了 - or operator
C()
is defined forT
这两者不能同时出现,否则会出现 "模糊" 的错误
注意隐式转换的使用
隐式转换的风险:可能导致程序行为不符合预期,特别是在复杂的代码中,隐式转换可能在不经意间被触发。
显式转换的好处:通过显式声明转换函数,可以更好地控制何时以及如何进行类型转换,从而减少潜在的错误和问题。