C++ 运算符重载的基本规则和习惯用法是什么?
注意:答案是按特定顺序给出的,但由于许多用户根据投票而不是给出的时间对答案进行排序,因此以下是答案的索引,以最有意义的顺序排列:C++ 运算符重载的基本规则和习惯用法是什么?,c++,operators,operator-overloading,c++-faq,C++,Operators,Operator Overloading,C++ Faq,注意:答案是按特定顺序给出的,但由于许多用户根据投票而不是给出的时间对答案进行排序,因此以下是答案的索引,以最有意义的顺序排列: 赋值运算符 输入和输出运算符 函数调用运算符 比较运算符 算术运算符 数组下标 类指针类型的运算符 (注意:这是一个条目。如果您想对在此表单中提供常见问题解答的想法提出批评,则可以在此处进行评论。该问题的答案将在中进行监控,其中常见问题解答的想法首先从中开始,因此您的答案很可能会被提出此想法的人阅读。) C++中运算符重载的三个基本规则 在C++中运
- 赋值运算符
- 输入和输出运算符
- 函数调用运算符
- 比较运算符
- 算术运算符
- 数组下标
- 类指针类型的运算符
基本上,重载操作符的首要规则的核心是:不要这样做。这可能看起来很奇怪,因为关于运算符重载还有很多需要了解的地方,所以很多文章、书籍章节和其他文本都涉及到了这一切。但是,尽管这似乎是显而易见的证据,但只有少数情况下操作符重载是合适的。原因是,实际上很难理解运算符应用程序背后的语义,除非在应用程序域中使用运算符是众所周知且无可争议的。与普遍的看法相反,情况几乎从未如此
C++对过载操作符的语义没有限制。编译器将乐于接受实现二进制
+
运算符以从其右操作数中减去的代码。然而,这种运算符的用户决不会怀疑表达式a+b
从b
中减去a
。当然,这假定应用程序域中运算符的语义是无可争议的
操作员之间以及与其他操作相关。如果您的类型支持
a+b
,则用户也可以调用a+=b
。如果它支持前缀增量++a
,那么他们希望a++
也能工作。如果他们能够检查a
,他们肯定也希望能够检查a>b
。如果他们可以复制您的类型,他们希望赋值也能起作用
继续>
C++中运算符重载的一般语法不能更改C++中内置类型的运算符的含义,运算符只能为用户定义类型1重载。也就是说,至少一个操作数必须是用户定义的类型。与其他重载函数一样,对于某一组参数,运算符只能重载一次
<>并非所有操作符都可以在C++中重载。在不能重载的操作符中有:<代码> ./COD> <代码>::<代码> > sieOS/<代码>代码> Type ID >代码> >代码> *>代码> C++中的唯一三元运算符,<代码>:<代码> < /P> <>在C++中可以重载的操作符是:std::ostream& operator<<(std::ostream& os, const T& obj)
{
// write obj to stream
return os;
}
std::istream& operator>>(std::istream& is, T& obj)
{
// read obj from stream
if( /* no valid object of T found in stream */ )
is.setstate(std::ios::failbit);
return is;
}
void* operator new(std::size_t) throw(std::bad_alloc);
void operator delete(void*) throw();
void* operator new[](std::size_t) throw(std::bad_alloc);
void operator delete[](void*) throw();
- 算术运算符:
+/code>
-
*
/
和%
+=
-=
*=
(所有二进制中缀)<代码>+%=
(一元前缀)<代码>++-
(一元前缀和后缀)--
- 位操作:
&
^
和
&=
^=
(一元前缀)
(所有二进制中缀)<代码>~=
- 布尔代数:
=
=
=
| |
(所有二进制中缀)<代码>代码>(一元前缀)&&
- 内存管理:
new
new[]
delete
delete[]
- 隐式转换运算符
- 杂项:
=
[]
->
->*
(所有二进制中缀)<代码>*,
(所有一元前缀)&
(函数调用,n元中缀)()
@
3可以作为operator@(x)
或x.operator@()
调用。应用于对象x
和y
的二进制中缀运算符@
,称为运算符(x,y)
class foo {
public:
// Overloaded call operator
int operator()(const std::string& y) {
// ...
}
};
foo f;
int a = f("hello");
inline bool operator==(const X& lhs, const X& rhs){ /* do actual comparison */ }
inline bool operator!=(const X& lhs, const X& rhs){return !operator==(lhs,rhs);}
inline bool operator< (const X& lhs, const X& rhs){ /* do actual comparison */ }
inline bool operator> (const X& lhs, const X& rhs){return operator< (rhs,lhs);}
inline bool operator<=(const X& lhs, const X& rhs){return !operator> (lhs,rhs);}
inline bool operator>=(const X& lhs, const X& rhs){return !operator< (lhs,rhs);}
bool operator<(const X& rhs) const { /* do actual comparison with *this */ }
class X {
X& operator++()
{
// do actual increment
return *this;
}
X operator++(int)
{
X tmp(*this);
operator++();
return tmp;
}
};
class X {
X& operator+=(const X& rhs)
{
// actual addition of rhs to *this
return *this;
}
};
inline X operator+(X lhs, const X& rhs)
{
lhs += rhs;
return lhs;
}
class X {
value_type& operator[](index_type idx);
const value_type& operator[](index_type idx) const;
// ...
};
class X {
value_type& operator[](index_type idx);
value_type operator[](index_type idx) const;
// ...
};
class my_ptr {
value_type& operator*();
const value_type& operator*() const;
value_type* operator->();
const value_type* operator->() const;
};
enum Month {Jan, Feb, ..., Nov, Dec}
void* operator new(std::size_t) throw(std::bad_alloc);
void operator delete(void*) throw();
void* operator new[](std::size_t) throw(std::bad_alloc);
void operator delete[](void*) throw();
class X { /* ... */ };
char buffer[ sizeof(X) ];
void f()
{
X* p = new(buffer) X(/*...*/);
// ...
p->~X(); // call destructor
}
void* operator new(std::size_t,void* p) throw(std::bad_alloc);
void operator delete(void* p,void*) throw();
void* operator new[](std::size_t,void* p) throw(std::bad_alloc);
void operator delete[](void* p,void*) throw();
class my_class {
public:
// ...
void* operator new();
void operator delete(void*,std::size_t);
void* operator new[](size_t);
void operator delete[](void*,std::size_t);
// ...
};
class my_string {
public:
operator const char*() const {return data_;} // This is the conversion operator
private:
const char* data_;
};
void f(const char*);
my_string str;
f(str); // same as f( str.operator const char*() )
void f(my_string&);
void f(const char*);
f(my_string());
class my_string {
public:
explicit operator const char*() const {return data_;}
private:
const char* data_;
};
prog.cpp: In function ‘int main()’:
prog.cpp:15:18: error: no matching function for call to ‘f(my_string)’
prog.cpp:15:18: note: candidates are:
prog.cpp:11:10: note: void f(my_string&)
prog.cpp:11:10: note: no known conversion for argument 1 from ‘my_string’ to ‘my_string&’
prog.cpp:12:10: note: void f(const char*)
prog.cpp:12:10: note: no known conversion for argument 1 from ‘my_string’ to ‘const char*’
struct Foo
{
int a;
double b;
std::ostream& operator<<(std::ostream& out) const
{
return out << a << " " << b;
}
};
Foo f = {10, 20.0};
std::cout << f;
Foo f = {10, 20.0};
f << std::cout
struct Foo
{
int a;
double b;
};
std::ostream& operator<<(std::ostream& out, Foo const& f)
{
return out << f.a << " " << f.b;
}
Foo f = {10, 20.0};
std::cout << f;