运算符重载(终)
● 类型转换运算符
– 函数声明为 operator type() const
– 与单参数构造函数一样,都引入了一种类型转换方式
struct Str
{
Str(int p)
: val(p)
{}
operator int() const //重载类型转换运算符: 没有显示声明返回类型(返回类型在函数名)、函数名后声明为const(不改变对象的内容,兼容常量与变量)
{
return val;
}
private:
int val;
};
int main()
{
Str obj(100); //调用构造函数
int v = obj;
std::cout << v << std::endl;
std::cout << static_cast<Str>(100) << std::endl; //OK,由于单参数构造函数和类型转换运算符
std::cout << static_cast<int>(obj) << std::endl; //OK,由于类型转换运算符
return 0;
}
– 注意避免引入歧义性与意料之外的行为
struct Str
{
Str(int p)
: val(p)
{}
operator int() const
{
return val;
}
friend auto operator+(Str a, Str b)
{
return Str(a.val + b.val);
}
private:
int val;
};
int main()
{
Str obj(100);
obj + 3; //Error: use of overloaded operator '+' is ambiguous(with operand types 'Str' and 'int')
//没有完美匹配,即无需任何类型转换就可以调用的重载函数,但是有两种解决办法
//第一种: 通过单一参数的构造函数将3转换为Str类型的对象,然后执行加法运算
//第二种: 通过重载类型转换运算符函数将obj转换为int类型,然后执行加法运算
//单一参数的构造函数和重载类型转换运算符函数的优先级相同,编译器无法确定选取哪一种
std::cin << 3; //#1Error: Invalid operands to binary expression('std::istream'(aka 'basic_istream<char>') and 'int'
//C++内部防止了隐式类型转换,比如if(std::cin)中std::cin输入流不能隐式转换为布尔类型
//如果不防止,#1处的std::cin会隐式转换为bool类型,然后进行类型提升转换为int类型,然后<< 3的含义就是左移3
return 0;
}
● 通过 explicit 引入显式类型转换
struct Str
{
explicit Str(int p) //explicit声明符表明不能隐式将int类型转换为Str类型
: val(p)
{}
operator int() const
{
return val;
}
friend auto operator+(Str a, Str b)
{
return Str(a.val + b.val);
}
private:
int val;
};
int main()
{
Str obj(100);
std::cout << obj + 3 << std::endl; //OK,通过重载类型转换运算符函数将obj转换为int类型,然后执行加法运算
return 0;
}
struct Str
{
Str(int p)
: val(p)
{}
explicit operator int() const //explicit声明符表明不能隐式将Str类型转换为int类型
{
return val;
}
friend auto operator+(Str a, Str b)
{
return Str(a.val + b.val);
}
private:
int val;
};
int main()
{
Str obj(100);
std::cout << int(obj + 3) << std::endl; //OK,通过单一参数的构造函数将3转换为Str类型的对象,再通过重载类型转换运算符函数将obj转换为int类型,然后执行加法运算
return 0;
}
struct Str
{
explicit Str(int p) //explicit声明符表明不能隐式将int类型转换为Str类型
: val(p)
{}
explicit operator int() const //explicit声明符表明不能隐式将Str类型转换为int类型
{
return val;
}
friend auto operator+(Str a, Str b)
{
return Str(a.val + b.val);
}
private:
int val;
};
int main()
{
Str obj(100);
std::cout << int(obj + 3) << std::endl; //Error: Invalid operands to binary expression('Str' and 'int')
obj + static_cast<Str>(3); //OK
static_cast<int>(obj) + 3; //OK
return 0;
}
– explicit bool 的特殊性:用于条件表达式时会进行隐式类型转换
struct Str
{
explicit Str(int p)
: val(p)
{}
operator bool() const //无explicit声明符
{
return (val == 0);
}
private:
int val;
};
int main()
{
Str obj(100);
std::cout << obj << std::endl; //OK
return 0;
}
struct Str
{
explicit Str(int p)
: val(p)
{}
explicit operator bool() const //explicit声明符,不允许隐式类型转换
{
return (val == 0);
}
private:
int val;
};
int main()
{
Str obj(100);
if(obj) //OK,等价于static_cast<bool>(obj)
{
std::cout << 1 <<std::endl;
}
else
{
std::cout << 0 <<std::endl;
}
auto var = obj ? 1 : 0; //OK,等价于static_cast<bool>(obj)
std::cout << var <<std::endl;
return 0;
}
● C++ 20 中对 == 与 <=> 的重载
– 通过 == 定义 !=
struct Str
{
Str(int p)
: val(p)
{}
friend bool operator==(Str obj1, Str obj2)
{
return obj1.val == obj2.val;
}
private:
int val;
};
int main()
{
Str obj(100);
Str obj2(100);
std::cout << (obj == obj2) << std::endl;
std::cout << (obj != obj2) << std::endl; //C++20 OK等价于((!operator==(Str(obj), Str(obj2)))),但是C++17 Error: Invalid operands to binary expression ('Str' and 'Str')
return 0;
}
struct Str
{
Str(int p)
: val(p)
{}
friend bool operator==(Str obj1, Str obj2)
{
return obj1.val == obj2.val;
}
friend bool operator!=(Str obj1, Str obj2)
{
return obj1.val != obj2.val;
}
private:
int val;
};
int main()
{
Str obj(100);
Str obj2(100);
std::cout << (obj == obj2) << std::endl; //OK
std::cout << (obj != obj2) << std::endl; //OK等价于((operator!=(Str(obj), Str(obj2))))
return 0;
}
但是不能通过!=定义==
struct Str
{
Str(int p)
: val(p)
{}
friend bool operator!=(Str obj1, Str obj2)
{
return obj1.val != obj2.val;
}
private:
int val;
};
int main()
{
Str obj(100);
Str obj2(100);
std::cout << (obj == obj2) << std::endl; //Error: Invalid operands to binary expression ('Str' and 'Str')
std::cout << (obj != obj2) << std::endl; //OK等价于((operator!=(Str(obj), Str(obj2))))
return 0;
}
struct Str
{
Str(int p)
: val(p)
{}
friend bool operator==(Str obj1, int x) //重载==运算符第一个参数是Str类型
{
return obj1.val == x;
}
private:
int val;
};
int main()
{
Str obj(100);
std::cout << (obj == 100) << std::endl; //OK
std::cout << (100 == obj) << std::endl; //C++20 OK因为通常等号满足交换律,因此C++20会尝试通过operator(int ,Str)寻找operator(Str, int),但是C++17Error: Invalid operands to binary expression ('int' and 'Str')
std::cout << (100 != obj) << std::endl; //C++20 OK通过operator==()再求反
return 0;
}
– 通过 <=> 定义多种比较逻辑
#include<iostream>
#include<compare>
struct Str
{
Str(int p)
: val(p)
{}
auto operator<=>(int x)
{
return val <=> x;
}
private:
int val;
};
int main()
{
Str obj(100);
std::cout << (100 >= obj) << std::endl; //OK等价于((operator>=(__cmp_cat::__unspec(0), obj.operator<=>(100))))
std::cout << (obj >= 100) << std::endl; //OK等价于((operator>=(obj.operator<=>(100), __cmp_cat::__unspec(0))))
return 0;
}
– 隐式交换操作数
– 注意 <=> 可返回的类型: strong_ordering, week_ordering, partial_ordering
参考
深蓝学院: C++基础与深度解析
cppinsights