精华内容
下载资源
问答
  • c++中不能被重载运算符有:1. .点2. ,逗号3. .* 4. ::5. ?:6.sizeof7.typeid

    c++中不能被重载的运算符有:

    1. .点

    2. ,逗号

    3.  .* 

    4.  ::

    5. ?:

    6.sizeof

    7.typeid

    展开全文
  • 运算符重载是C++极为重要的语言特性之一,本文将用代码实例回答——C++哪些运算符可以重载?如何重载?实现运算符重载时需要注意哪些? 哪些运算符可以重载,哪些不可重载? C++98,C++0x,C++11对“哪些运算符...

    运算符重载是C++极为重要的语言特性之一,本文将用代码实例回答——C++哪些运算符可以重载?如何重载?实现运算符重载时需要注意哪些?


    哪些运算符可以重载,哪些不可重载?

    C++98,C++0x,C++11对“哪些运算符重载可以重载”有一致的规定,具体如下:


    其中,很少使用的是“,”(逗号运算符)。


    标准同样规定了不可重载的运算符


    其中,“::”是作用域运算符,

    “?:”是条件运算符。


    两个较少使用的运算符是 .* 和 ->* 分别是:

    .* 对象调用成员函数指针;

    ->* 对象指针调用成员函数指针;


    标准还指出,有的运算符可以同时支持“一元运算”和“二元运算”:





    下文通过实现几个模拟内置类型的类来展示具体的运算符重载方法应当如何实现。


    一些注意事项

    实现运算符重载时应注意:

    1. 运算符重载不改变运算符的优先级与结合性,如/的优先级比-高;
    2. 运算符重载不改变部分运算符对操作数个数的限制,如+只能有两个操作数;


    模拟整型Integer

    回想一下C++里整型支持支持那些运算?具体有:

    算术运算:

    正,如 +a;负,如 -a;

    加,如 a + b;减,如 a - b;乘,如 a * b;除,如 a / b;取余(模),如 a % b;


    自增自减(整型特有):

    自增,如 a++,++a;自减,如 a--,--a;


    比较运算:

    大于,如 a > b;小于,如 a < b;

    等于,如 a == b;不等于,如 a != b;

    大于等于,如 a >= b;小于等于,如 a <= b;


    位运算:

    按位取反,如 ~a;

    左移,如 a << 2;右移,如 a >> 3;

    按位与,如 a & b;按位或,如 a | b;按位异或,如 a ^ b;


    赋值运算:

    赋值,a = 5;


    复合赋值:

    +=,-=,*=,/=,%=,(算数运算与赋值运算复合)

    &=,|=,^=,<<=,>>=,(位运算与赋值运算复合)


    下面是这个Integer的代码:

    class Integer
    {
    public:
    	Integer(int ival) : value(ival) {}
    	Integer(const Integer& iobj) : value(iobj.value) {}
    	
    	// operator int() { return value; } // conversion to built-in int
    
    	Integer operator+() const { return Integer(value); }
    	Integer operator-() const { return Integer(-value); }
    	
    	Integer operator+(const Integer& rhs) const { return Integer(value + rhs.value); }
    	Integer operator-(const Integer& rhs) const { return Integer(value - rhs.value); }
    	Integer operator*(const Integer& rhs) const { return Integer(value * rhs.value); }
    	Integer operator/(const Integer& rhs) const { return Integer(value / rhs.value); }
    	Integer operator%(const Integer& rhs) const { return Integer(value % rhs.value); }
    	
    	// prefix
    	Integer operator++() { return Integer(++value); }
    	Integer operator--() { return Integer(--value); }
    	
    	// suffix
    	Integer operator++(int) { int old = value; value++; return Integer(old); }
    	Integer operator--(int) { int old = value; value--; return Integer(old); }
    
    	// compare:
    	bool operator<(const Integer& rhs) const { return value < rhs.value; }
    	bool operator>(const Integer& rhs) const { return value > rhs.value; }
    	bool operator==(const Integer& rhs) const { return value == rhs.value; }
    	bool operator!=(const Integer& rhs) const { return value != rhs.value; }
    	bool operator<=(const Integer& rhs) const { return value <= rhs.value; }
    	bool operator>=(const Integer& rhs) const { return value >= rhs.value; }
    	
    	// bit operations:
    	Integer operator~() const { return Integer(~value); }
    	Integer operator<<(unsigned n) const { return Integer(value << n); }
    	Integer operator>>(unsigned n) const { return Integer(value >> n); }
    	Integer operator&(const Integer& rhs) const { return Integer(value & rhs.value); }
    	Integer operator|(const Integer& rhs) const { return Integer(value | rhs.value); }
    	Integer operator^(const Integer& rhs) const { return Integer(value ^ rhs.value); }
    
    	// assignment:
    	Integer operator=(const Integer& rhs) { return value = rhs.value; }
    	// compound assignment:
    	Integer operator+=(const Integer& rhs) { return value += rhs.value; }
    	Integer operator-=(const Integer& rhs) { return value -= rhs.value; }
    	Integer operator*=(const Integer& rhs) { return value *= rhs.value; }
    	Integer operator/=(const Integer& rhs) { return value /= rhs.value; }
    	Integer operator%=(const Integer& rhs) { return value %= rhs.value; }
    	Integer operator&=(const Integer& rhs) { return value &= rhs.value; }
    	Integer operator|=(const Integer& rhs) { return value |= rhs.value; }
    	Integer operator^=(const Integer& rhs) { return value ^= rhs.value; }
    	Integer operator<<=(const Integer& rhs) { return value <<= rhs.value; }
    	Integer operator>>=(const Integer& rhs) { return value >>= rhs.value; }
    // private:
    	int value;
    };

    实现运算符重载函数时,需要注意的是末尾是否要加const?
    这取决与操作是否会改变当前对象的成员值,如果不改变则不加,改变则加。

    Integer类只是为了展示如何使用运算符重载,并没有多少实用价值。

    一下是Integer类的测试:

    void testInteger()
    {
    	Integer i = 123;
    
    #define SEPRATER ":\t"
    #define TRACE_INTEGER(iobj) printf(#iobj SEPRATER "%d\n", (iobj).value) 
    #define TRACE_BOOL(exp) printf(#exp SEPRATER "%s\n", (exp) ? "true" : "false")
    #define TRACE_HEX(iobj) printf(#iobj SEPRATER "%p\n", (iobj).value)
    
    	TRACE_INTEGER(i);
    	TRACE_INTEGER(+i);
    	TRACE_INTEGER(-i);
    	
    	Integer j = 5;
    	TRACE_INTEGER(i+j);
    	TRACE_INTEGER(i-j);
    	TRACE_INTEGER(i*j);
    	TRACE_INTEGER(i/j);
    	TRACE_INTEGER(i%j);
    	
    	TRACE_INTEGER(++i); TRACE_INTEGER(i);
    	TRACE_INTEGER(--i); TRACE_INTEGER(i);
    	TRACE_INTEGER(i++); TRACE_INTEGER(i);
    	TRACE_INTEGER(i--); TRACE_INTEGER(i);
    	
    	TRACE_BOOL(i>j);
    	TRACE_BOOL(i<j);
    	TRACE_BOOL(i==j);
    	TRACE_BOOL(i!=j);
    	TRACE_BOOL(i>=j);
    	TRACE_BOOL(i<=j);
    	
    	TRACE_HEX(i);
    	TRACE_HEX(~i);
    	TRACE_HEX(i<<4);
    	TRACE_HEX(i>>4);
    	TRACE_HEX(i<<24);
    	
    	TRACE_HEX(i & ~0xF); // i & ~0xF <<== same as ==>> i & Integer(~0xF), because C++ implicit conversion.
    	TRACE_HEX(i | 0xF0);
    	TRACE_HEX(i ^ 0xF0);
    	
    	TRACE_INTEGER(i);
    	TRACE_INTEGER(j);
    	TRACE_INTEGER(i=j);
    	
    	TRACE_INTEGER(i+=j);
    	TRACE_INTEGER(i-=j);
    	TRACE_INTEGER(i*=j);
    	TRACE_INTEGER(i/=j);
    	
    	j = 3;
    	TRACE_INTEGER(i%=j);
    }
    该测试的输出如下:

    i:	123
    +i:	123
    -i:	-123
    i+j:	128
    i-j:	118
    i*j:	615
    i/j:	24
    i % :	3
    ++i:	124
    i:	124
    --i:	123
    i:	123
    i++:	123
    i:	124
    i--:	124
    i:	123
    i>j:	true
    i<j:	false
    i==j:	false
    i!=j:	true
    i>=j:	true
    i<=j:	false
    i:	0000007B
    ~i:	FFFFFF84
    i<<4:	000007B0
    i>>4:	00000007
    i<<24:	7B000000
    i & ~0xF:	00000070
    i | 0xF0:	000000FB
    i ^ 0xF0:	0000008B
    i:	123
    j:	5
    i=j:	5
    i+=j:	10
    i-=j:	5
    i*=j:	25
    i/=j:	5
    i%=j:	2


    模拟指针Pointer

    再回想一下原生的指针支持那些运算?

    具体有:

    *,解引用,从T*得到T

    [],下标运算

    ++,自增

    --,自减

    +,加法

    -,减法

    有一点值得注意的是:

    1. 每种类型都对应一种指针,如int对应int*;
    2. 解引用和下标运算的返回结果可以做“左值”(赋值运算符左边的值,即可以赋值);
    3. 指针的加减,-是以指针当前类型的大小为单位的,即:若有指针p,则 (size_t)(p + 1) == (size_t)p + sizeof(*p)

    要实现1,Pointer类型必须实现为类模板;

    Pointer实现为类模板,它的数据成员(data member)就可以是原生指针,可以很自然的支持原生指针的加减运算。

    据此实现的Pointer类如下:

    template <typename T>
    class Pointer 
    {
    public:
    	Pointer() : ptr_(0) {}
    	Pointer(T* ptr) : ptr_(ptr) {}
    	
    	// operator T*() { return ptr_; } // implicit conversion.
    	T* get() const { return ptr_; }	
    	
    	T& operator*() const { return *ptr_; }
    	T* operator->() const { return ptr_; printf("operator->()\n"); }
    	T& operator[](int offset) const { return ptr_[offset]; }
    	
    	Pointer<T> operator++() { return Pointer(++ptr_); } // prefix
    	Pointer<T> operator--() { return Pointer(--ptr_); } // prefix
    	
    	Pointer<T> operator++(int) { return Pointer(ptr_++); } // suffix
    	Pointer<T> operator--(int) { return Pointer(ptr_--); } // suffix
    	
    	Pointer<T> operator+=(int off) { return Pointer(ptr_ += off); }
    	Pointer<T> operator-=(int off) { return Pointer(ptr_ -= off); }
    	
    	Pointer<T> operator+(int off) const { return Pointer(ptr_ + off); }
    	Pointer<T> operator-(int off) const { return Pointer(ptr_ - off); }
    // private:
    	T* ptr_;
    };

    Pointer类仅模拟指针的一般运算,并没有考虑“通过指针进行资源管理”这一主题,所有也没有保证delete ptr的实际行为。


    以下是该类的测试程序:

    template<typename T>
    ostream& operator<<(ostream& out, const Pointer<T>& ptr)
    {
    	out << ptr.ptr_;
    	return out;	
    }
    
    //#define TRACE(fmt, exp) printf(#exp ":\t" fmt, (exp))
    #define TRACE(exp) cout << #exp << ":\t" << (exp) << endl
    #define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
    
    int ia[] = { 123, 456, 789, 111, 222, 333 };
    
    void testPointer()
    {
    	for(int i=0; i<ARRAY_SIZE(ia); ++i) {
    		printf("%p: %d\n", &ia[i], ia[i]);
    	}
    
    	Pointer<int> ptr = &ia[0];
    	
    	TRACE(ptr);
    	TRACE(ia);
    	TRACE(*ptr);
    	TRACE(ptr[1]);
    	
    	TRACE(++ptr); TRACE(*ptr);
    	TRACE(--ptr); TRACE(*ptr);
    	
    	TRACE(ptr++); TRACE(*ptr);
    	TRACE(ptr--); TRACE(*ptr);
    	
    	TRACE(ptr+=2); TRACE(*ptr);
    	TRACE(ptr-=2); TRACE(*ptr);
    	
    	ptr = &ia[3];
    	TRACE(ptr+2); TRACE(*(ptr+2));
    	TRACE(ptr-2); TRACE(*(ptr-2));
    	
    	ptr[0] = 555;
    	TRACE(ptr[0]);
    	
    	*ptr = 666;
    	TRACE(*ptr);
    }

    测试程序的输出如下:

    0x603090: 123
    0x603094: 456
    0x603098: 789
    0x60309c: 111
    0x6030a0: 222
    0x6030a4: 333
    ptr:	0x603090
    ia:	0x603090
    *ptr:	123
    ptr[1]:	456
    ++ptr:	0x603094
    *ptr:	456
    --ptr:	0x603090
    *ptr:	123
    ptr++:	0x603090
    *ptr:	456
    ptr--:	0x603094
    *ptr:	123
    ptr+=2:	0x603098
    *ptr:	789
    ptr-=2:	0x603090
    *ptr:	123
    ptr+2:	0x6030a4
    *(ptr+2):	333
    ptr-2:	0x603094
    *(ptr-2):	456
    ptr[0]:	555
    *ptr:	666


    上面的测试testPointer并没有用到operator->,下面单独测试operator->:

    struct Foo 
    {
    	int id;
    	static int count;
    	
    	Foo() : id(++count) { printf("Foo::Foo(%p)\n", this); }
    	~Foo() { printf("Foo::~Foo(%p)\n", this); }
    	
    	void show() { printf("Foo.show(%p): %d\n", this, id); }
    };
    
    int Foo::count = 0;
    
    void testAccess()
    {
    	printf("\n%s():\n", __FUNCTION__);
    	Pointer<Foo> fptr = new Foo();
    	
    	// test operator->
    	fptr->show();     // access member function.
    	TRACE(fptr->id);  // access data member.
    	
    	delete fptr.get();
    }
    该测试程序的输出为:

    testAccess():
    Foo::Foo(0x133a010)
    Foo.show(0x133a010): 1
    fptr->id:	1
    Foo::~Foo(0x133a010)


    几种特殊运算符的重载

    上面的两个类基本已经覆盖了大部分的运算符重载,下面展示几个“罕见”的运算符重载:

    #define TRACE_CALL puts(__FUNCTION__)
    class Operand
    {
    public:
    	void operator,(const Operand& rhs) const { TRACE_CALL; }
    	void operator,(int a) const { TRACE_CALL; }
    	// void operator,(int a, int b) const { TRACE_CALL; } // ERROR: operator, 有且仅有一个参数
    	void operator->*(int a) const { printf("%s(%d)\n", __FUNCTION__, a); }
    };
    测试程序:

    void testOperand()
    {
    	Operand op1, op2;
    
    	op1, op2;  // operator,
    	op1->*123; // operator->*
    }

    程序输出:

    operator,
    operator->*(123)

    operator new与operator delete

    关于operator new和operator delete的重载,下次另外写博客阐释。

    转载于:https://my.oschina.net/u/737017/blog/349630

    展开全文
  • C++哪些运算符重载能够重载?

    千次阅读 2018-09-04 09:13:53
    运算符重载是C++极为重要的语言特性之中的一个。本文将用代码实例回答——C++哪些运算符能够重载?怎样重载?实现运算符重载时须要注意哪些?   哪些运算符能够重载,哪些不可重载? C++98,C++0x,C++11对...

    运算符重载是C++极为重要的语言特性之中的一个。本文将用代码实例回答——C++哪些运算符能够重载?怎样重载?实现运算符重载时须要注意哪些?

     

    哪些运算符能够重载,哪些不可重载?

    C++98,C++0x,C++11对“哪些运算符重载能够重载”有一致的规定。详细例如以下:

    当中,非常少使用的是“,”(逗号运算符)。

     

     

    标准相同规定了不可重载的运算符

    当中,“::”是作用域运算符。

    “?:”是条件运算符。

     

    两个较少使用的运算符是 .* 和 ->* 各自是:

    .* 对象调用成员函数指针;

    ->* 对象指针调用成员函数指针。

     

    标准还指出,有的运算符能够同一时候支持“一元运算”和“二元运算”:

     

     

     

    下文通过实现几个模拟内置类型的类来展示详细的运算符重载方法应当怎样实现。

     

     

    一些注意事项

    实现运算符重载时应注意:

    1. 运算符重载不改变运算符的优先级与结合性,如/的优先级比-高;
    2. 运算符重载不改变部分运算符对操作数个数的限制,如+仅仅能有两个操作数;

     

    模拟整型Integer

    回忆一下C++里整型支持支持那些运算?详细有:

    算术运算:

     

    正。如 +a;负,如 -a;

    加,如 a + b;减,如 a - b;乘。如 a * b;除。如 a / b。取余(模),如 a % b;

     

    自增自减(整型特有):

    自增,如 a++,++a;自减,如 a--,--a;

     

    比較运算:

    大于,如 a > b;小于,如 a < b;

    等于。如 a == b。不等于,如 a != b。

    大于等于。如 a >= b。小于等于。如 a <= b。

     

    位运算:

    按位取反。如 ~a。

    左移,如 a << 2。右移,如 a >> 3;

    按位与,如 a & b。按位或,如 a | b;按位异或,如 a ^ b;

     

    赋值运算:

    赋值。a = 5;

     

    复合赋值:

    +=。-=,*=,/=,%=,(算数运算与赋值运算复合)

    &=。|=,^=,<<=,>>=。(位运算与赋值运算复合)

     

    以下是这个Integer的代码:

     

    class Integer
    {
    public:
    	Integer(int ival) : value(ival) {}
    	Integer(const Integer& iobj) : value(iobj.value) {}
    	
    	// operator int() { return value; } // conversion to built-in int
    
    	Integer operator+() const { return Integer(value); }
    	Integer operator-() const { return Integer(-value); }
    	
    	Integer operator+(const Integer& rhs) const { return Integer(value + rhs.value); }
    	Integer operator-(const Integer& rhs) const { return Integer(value - rhs.value); }
    	Integer operator*(const Integer& rhs) const { return Integer(value * rhs.value); }
    	Integer operator/(const Integer& rhs) const { return Integer(value / rhs.value); }
    	Integer operator%(const Integer& rhs) const { return Integer(value % rhs.value); }
    	
    	// prefix
    	Integer operator++() { return Integer(++value); }
    	Integer operator--() { return Integer(--value); }
    	
    	// suffix
    	Integer operator++(int) { int old = value; value++; return Integer(old); }
    	Integer operator--(int) { int old = value; value--; return Integer(old); }
    
    	// compare:
    	bool operator<(const Integer& rhs) const { return value < rhs.value; }
    	bool operator>(const Integer& rhs) const { return value > rhs.value; }
    	bool operator==(const Integer& rhs) const { return value == rhs.value; }
    	bool operator!=(const Integer& rhs) const { return value != rhs.value; }
    	bool operator<=(const Integer& rhs) const { return value <= rhs.value; }
    	bool operator>=(const Integer& rhs) const { return value >= rhs.value; }
    	
    	// bit operations:
    	Integer operator~() const { return Integer(~value); }
    	Integer operator<<(unsigned n) const { return Integer(value << n); }
    	Integer operator>>(unsigned n) const { return Integer(value >> n); }
    	Integer operator&(const Integer& rhs) const { return Integer(value & rhs.value); }
    	Integer operator|(const Integer& rhs) const { return Integer(value | rhs.value); }
    	Integer operator^(const Integer& rhs) const { return Integer(value ^ rhs.value); }
    
    	// assignment:
    	Integer operator=(const Integer& rhs) { return value = rhs.value; }
    	// compound assignment:
    	Integer operator+=(const Integer& rhs) { return value += rhs.value; }
    	Integer operator-=(const Integer& rhs) { return value -= rhs.value; }
    	Integer operator*=(const Integer& rhs) { return value *= rhs.value; }
    	Integer operator/=(const Integer& rhs) { return value /= rhs.value; }
    	Integer operator%=(const Integer& rhs) { return value %= rhs.value; }
    	Integer operator&=(const Integer& rhs) { return value &= rhs.value; }
    	Integer operator|=(const Integer& rhs) { return value |= rhs.value; }
    	Integer operator^=(const Integer& rhs) { return value ^= rhs.value; }
    	Integer operator<<=(const Integer& rhs) { return value <<= rhs.value; }
    	Integer operator>>=(const Integer& rhs) { return value >>= rhs.value; }
    // private:
    	int value;
    };

     

    实现运算符重载函数时。须要注意的是末尾是否要加const?
    这取决与操作是否会改变当前对象的成员值。假设不改变则不加,改变则加。

    Integer类仅仅是为了展示怎样使用运算符重载,并没有多少有用价值。

    一下是Integer类的測试:

     

    void testInteger()
    {
    	Integer i = 123;
    
    #define SEPRATER ":\t"
    #define TRACE_INTEGER(iobj) printf(#iobj SEPRATER "%d\n", (iobj).value) 
    #define TRACE_BOOL(exp) printf(#exp SEPRATER "%s\n", (exp) ? "true" : "false")
    #define TRACE_HEX(iobj) printf(#iobj SEPRATER "%p\n", (iobj).value)
    
    	TRACE_INTEGER(i);
    	TRACE_INTEGER(+i);
    	TRACE_INTEGER(-i);
    	
    	Integer j = 5;
    	TRACE_INTEGER(i+j);
    	TRACE_INTEGER(i-j);
    	TRACE_INTEGER(i*j);
    	TRACE_INTEGER(i/j);
    	TRACE_INTEGER(i%j);
    	
    	TRACE_INTEGER(++i); TRACE_INTEGER(i);
    	TRACE_INTEGER(--i); TRACE_INTEGER(i);
    	TRACE_INTEGER(i++); TRACE_INTEGER(i);
    	TRACE_INTEGER(i--); TRACE_INTEGER(i);
    	
    	TRACE_BOOL(i>j);
    	TRACE_BOOL(i<j);
    	TRACE_BOOL(i==j);
    	TRACE_BOOL(i!=j);
    	TRACE_BOOL(i>=j);
    	TRACE_BOOL(i<=j);
    	
    	TRACE_HEX(i);
    	TRACE_HEX(~i);
    	TRACE_HEX(i<<4);
    	TRACE_HEX(i>>4);
    	TRACE_HEX(i<<24);
    	
    	TRACE_HEX(i & ~0xF); // i & ~0xF <<== same as ==>> i & Integer(~0xF), because C++ implicit conversion.
    	TRACE_HEX(i | 0xF0);
    	TRACE_HEX(i ^ 0xF0);
    	
    	TRACE_INTEGER(i);
    	TRACE_INTEGER(j);
    	TRACE_INTEGER(i=j);
    	
    	TRACE_INTEGER(i+=j);
    	TRACE_INTEGER(i-=j);
    	TRACE_INTEGER(i*=j);
    	TRACE_INTEGER(i/=j);
    	
    	j = 3;
    	TRACE_INTEGER(i%=j);
    }

    该測试的输出例如以下:

     

     

    i:	123
    +i:	123
    -i:	-123
    i+j:	128
    i-j:	118
    i*j:	615
    i/j:	24
    i % :	3
    ++i:	124
    i:	124
    --i:	123
    i:	123
    i++:	123
    i:	124
    i--:	124
    i:	123
    i>j:	true
    i<j:	false
    i==j:	false
    i!=j:	true
    i>=j:	true
    i<=j:	false
    i:	0000007B
    ~i:	FFFFFF84
    i<<4:	000007B0
    i>>4:	00000007
    i<<24:	7B000000
    i & ~0xF:	00000070
    i | 0xF0:	000000FB
    i ^ 0xF0:	0000008B
    i:	123
    j:	5
    i=j:	5
    i+=j:	10
    i-=j:	5
    i*=j:	25
    i/=j:	5
    i%=j:	2
    

     

     

    模拟指针Pointer

    再回忆一下原生的指针支持那些运算?

    详细有:

    *,解引用。从T*得到T

    [],下标运算

    ++,自增

    --,自减

    +,加法

    -,减法

    有一点值得注意的是:

     

    1. 每种类型都相应一种指针,如int相应int*;
    2. 解引用和下标运算的返回结果能够做“左值”(赋值运算符左边的值。即能够赋值)。
    3. 指针的加减,-是以指针当前类型的大小为单位的。即:若有指针p,则 (size_t)(p + 1) == (size_t)p + sizeof(*p)

     

    要实现1,Pointer类型必须实现为类模板;

    Pointer实现为类模板,它的数据成员(data member)就能够是原生指针,能够非常自然的支持原生指针的加减运算。

    据此实现的Pointer类例如以下:

     

    template <typename T>
    class Pointer 
    {
    public:
    	Pointer() : ptr_(0) {}
    	Pointer(T* ptr) : ptr_(ptr) {}
    	
    	// operator T*() { return ptr_; } // implicit conversion.
    	T* get() const { return ptr_; }	
    	
    	T& operator*() const { return *ptr_; }
    	T* operator->() const { return ptr_; printf("operator->()\n"); }
    	T& operator[](int offset) const { return ptr_[offset]; }
    	
    	Pointer<T> operator++() { return Pointer(++ptr_); } // prefix
    	Pointer<T> operator--() { return Pointer(--ptr_); } // prefix
    	
    	Pointer<T> operator++(int) { return Pointer(ptr_++); } // suffix
    	Pointer<T> operator--(int) { return Pointer(ptr_--); } // suffix
    	
    	Pointer<T> operator+=(int off) { return Pointer(ptr_ += off); }
    	Pointer<T> operator-=(int off) { return Pointer(ptr_ -= off); }
    	
    	Pointer<T> operator+(int off) const { return Pointer(ptr_ + off); }
    	Pointer<T> operator-(int off) const { return Pointer(ptr_ - off); }
    // private:
    	T* ptr_;
    };

     

     

    Pointer类仅模拟指针的一般运算,并没有考虑“通过指针进行资源管理”这一主题,全部也没有保证delete ptr的实际行为。

     

     

     

    下面是该类的測试程序:

    template<typename T>
    ostream& operator<<(ostream& out, const Pointer<T>& ptr)
    {
    	out << ptr.ptr_;
    	return out;	
    }
    
    //#define TRACE(fmt, exp) printf(#exp ":\t" fmt, (exp))
    #define TRACE(exp) cout << #exp << ":\t" << (exp) << endl
    #define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
    
    int ia[] = { 123, 456, 789, 111, 222, 333 };
    
    void testPointer()
    {
    	for(int i=0; i<ARRAY_SIZE(ia); ++i) {
    		printf("%p: %d\n", &ia[i], ia[i]);
    	}
    
    	Pointer<int> ptr = &ia[0];
    	
    	TRACE(ptr);
    	TRACE(ia);
    	TRACE(*ptr);
    	TRACE(ptr[1]);
    	
    	TRACE(++ptr); TRACE(*ptr);
    	TRACE(--ptr); TRACE(*ptr);
    	
    	TRACE(ptr++); TRACE(*ptr);
    	TRACE(ptr--); TRACE(*ptr);
    	
    	TRACE(ptr+=2); TRACE(*ptr);
    	TRACE(ptr-=2); TRACE(*ptr);
    	
    	ptr = &ia[3];
    	TRACE(ptr+2); TRACE(*(ptr+2));
    	TRACE(ptr-2); TRACE(*(ptr-2));
    	
    	ptr[0] = 555;
    	TRACE(ptr[0]);
    	
    	*ptr = 666;
    	TRACE(*ptr);
    }

     

     

    測试程序的输出例如以下:

     

    0x603090: 123
    0x603094: 456
    0x603098: 789
    0x60309c: 111
    0x6030a0: 222
    0x6030a4: 333
    ptr:	0x603090
    ia:	0x603090
    *ptr:	123
    ptr[1]:	456
    ++ptr:	0x603094
    *ptr:	456
    --ptr:	0x603090
    *ptr:	123
    ptr++:	0x603090
    *ptr:	456
    ptr--:	0x603094
    *ptr:	123
    ptr+=2:	0x603098
    *ptr:	789
    ptr-=2:	0x603090
    *ptr:	123
    ptr+2:	0x6030a4
    *(ptr+2):	333
    ptr-2:	0x603094
    *(ptr-2):	456
    ptr[0]:	555
    *ptr:	666
    



    以上測试testPointer并没实用到operator->,以下单独測试operator->:

     

     

    struct Foo 
    {
    	int id;
    	static int count;
    	
    	Foo() : id(++count) { printf("Foo::Foo(%p)\n", this); }
    	~Foo() { printf("Foo::~Foo(%p)\n", this); }
    	
    	void show() { printf("Foo.show(%p): %d\n", this, id); }
    };
    
    int Foo::count = 0;
    
    void testAccess()
    {
    	printf("\n%s():\n", __FUNCTION__);
    	Pointer<Foo> fptr = new Foo();
    	
    	// test operator->
    	fptr->show();     // access member function.
    	TRACE(fptr->id);  // access data member.
    	
    	delete fptr.get();
    }

    该測试程序的输出为:

     

     

    testAccess():
    Foo::Foo(0x133a010)
    Foo.show(0x133a010): 1
    fptr->id:	1
    Foo::~Foo(0x133a010)

     

    几种特殊运算符的重载

    上面的两个类基本已经覆盖了大部分的运算符重载,以下展示几个“罕见”的运算符重载:

    #define TRACE_CALL puts(__FUNCTION__)
    class Operand
    {
    public:
    	void operator,(const Operand& rhs) const { TRACE_CALL; }
    	void operator,(int a) const { TRACE_CALL; }
    	// void operator,(int a, int b) const { TRACE_CALL; } // ERROR: operator, 有且仅有一个參数
    	void operator->*(int a) const { printf("%s(%d)\n", __FUNCTION__, a); }
    };
    

    測试程序:

     

     

    void testOperand()
    {
    	Operand op1, op2;
    
    	op1, op2;  // operator,
    	op1->*123; // operator->*
    }

     

    程序输出:

     

    operator,
    operator->*(123)
    展开全文
  • 1、重载二元操作符的方法 二元运算符又称为双目运算符,即需要2个操作数的运算符,例如 +...运算符重载可以分为3种方式:类的非静态成员函数、类的友元函数、普通函数。 例如有 2 个操作数 a 和 b,二元运算符 ?

    来自:http://www.cnblogs.com/LubinLew/p/CppOperatorOverload-BinaryOperator.html

    1、重载二元操作符的方法

    二元运算符又称为双目运算符,即需要2个操作数的运算符,例如 + - * / 等。

    运算符重载可以分为3种方式:类的非静态成员函数、类的友元函数、普通函数。

    例如有 2 个操作数 a 和 b,二元运算符 ? (表示一个二元运算符),a ? b 的操作会被解释为下面2种形式之一 

    //a ? b
    a.operator?(b);    //类的非静态成员函数
    operator(a, b);  //友元函数 和 普通函数

     第一种形式是运算符被重载为类的非静态成员函数,

    这种方式要求运算符左边的的操作数(即第一个操作数a)必须是一个对象,operator?是这个对象的非静态成员函数

    并且只能有一个参数。

     

    第二种形式是运算符被重载为类的友元函数 或 普通函数,

    这种方式需要2个参数,

    重载为 类的友元函数 和 普通函数的区别是 类的友元函数可以直接访问类的私有成员,而普通函数不可以。

     

    2、应用举例(对象 ? 对象)

    下例中有3个complex类 ComplexA、ComplexB 和 ComplexC,3个类都重载了加减乘除 运算符。

    其中ComplexA使用类的非静态成员函数方式重载,ComplexB使用类的友元函数方式重载,ComplexC使用普通函数方式重载。

    需要注意的是复数的加减乘除运算的算法是有问题的,只是一个说明重载方法的例子,

    另外重载函数的参数最好使用const关键字限定,至于返回值是否用const限定,需要取决于你的设计,比如允许C3 = ++(C1+C2)这种情况,就不能用cosnt限定。

    至于不同类型的对象间的操作,通常是没有意义的。

    复制代码
    #include <iostream>
    using namespace std;
    
    class ComplexA
    {
    public:
        //默认构造函数(Default constructor)
        ComplexA(){cout<<"Default Constructor"<<endl;}
        //带参数的构造函数(The constructor with parameters)
        ComplexA(double re, double im):real(re),image(im){cout<<"Parameter Constructor"<<endl;}
        //拷贝构造函数(Copy constructor)
        ComplexA(const ComplexA& ref){real = ref.real; image = ref.image; cout<<"Copy Constructor"<<endl;}
        //析构函数(destructor)
        ~ComplexA(){cout<<"Destructor"<<endl;}
    
        //Operator Overload : +
        ComplexA operator+(ComplexA& ref)
        {
            return ComplexA(real + ref.real, image + ref.image);
        }
    
        //Operator Overload : -
        ComplexA operator-(ComplexA& ref)
        {
            return ComplexA(real - ref.real, image - ref.image);
        }
    
        //Operator Overload : *
        ComplexA operator*(ComplexA& ref)
        {
            return ComplexA(real * ref.real, image * ref.image);
        }
    
        //Operator Overload : /
        ComplexA operator/(ComplexA& ref)
        {
            return ComplexA(real / ref.real, image / ref.image);
        }
    
        //display
        void display(void){cout<<real<<"+"<<image<<"i"<<endl;}
    private:
        double real;    //复数的实部
        double image;   //复数的虚部
    };
    
    class ComplexB
    {
    public:
        //默认构造函数(Default constructor)
        ComplexB(){cout<<"Default Constructor"<<endl;}
        //带参数的构造函数(The constructor with parameters)
        ComplexB(double re, double im):real(re),image(im){cout<<"Parameter Constructor"<<endl;}
        //拷贝构造函数(Copy constructor)
        ComplexB(const ComplexB& ref){real = ref.real; image = ref.image; cout<<"Copy Constructor"<<endl;}
        //析构函数(destructor)
        ~ComplexB(){cout<<"Destructor"<<endl;}
    
        //Operator Overload : +
        friend ComplexB operator+(ComplexB& ref1, ComplexB& ref2)
        {
            return ComplexB(ref1.real + ref2.real, ref1.image + ref2.image);
        }
    
        //Operator Overload : -
        friend ComplexB operator-(ComplexB& ref1, ComplexB& ref2)
        {
            return ComplexB(ref1.real - ref2.real, ref1.image - ref2.image);
        }
    
        //Operator Overload : *
        friend ComplexB operator*(ComplexB& ref1, ComplexB& ref2)
        {
            return ComplexB(ref1.real * ref2.real, ref1.image * ref2.image);
        }
    
        //Operator Overload : /
        friend ComplexB operator/(ComplexB& ref1, ComplexB& ref2)
        {
            return ComplexB(ref1.real / ref2.real, ref1.image / ref2.image);
        }
    
        //display
        void display(void){cout<<real<<"+"<<image<<"i"<<endl;}
    private:
        double real;    //复数的实部
        double image;   //复数的虚部
    };
    
    
    class ComplexC
    {
    public:
        //默认构造函数(Default constructor)
        ComplexC(){cout<<"Default Constructor"<<endl;}
        //带参数的构造函数(The constructor with parameters)
        ComplexC(double re, double im):real(re),image(im){cout<<"Parameter Constructor"<<endl;}
        //拷贝构造函数(Copy constructor)
        ComplexC(const ComplexC& ref){real = ref.real; image = ref.image; cout<<"Copy Constructor"<<endl;}
        //析构函数(destructor)
        ~ComplexC(){cout<<"Destructor"<<endl;}
    
        //Get Data
        double GetReal(void){return real;}
        double GetImage(void){return image;}
    
      //display
        void display(void){cout<<real<<"+"<<image<<"i"<<endl;}
    private:
        double real;    //复数的实部
        double image;   //复数的虚部
    };
    
    //Operator Overload : +
    ComplexC operator+(ComplexC& ref1, ComplexC& ref2)
    {
        return ComplexC(ref1.GetReal() + ref2.GetReal(), ref1.GetImage() + ref2.GetImage());
    }
    
    //Operator Overload : -
    ComplexC operator-(ComplexC& ref1, ComplexC& ref2)
    {
        return ComplexC(ref1.GetReal() - ref2.GetReal(), ref1.GetImage() - ref2.GetImage());
    }
    
    //Operator Overload : *
    ComplexC operator*(ComplexC& ref1, ComplexC& ref2)
    {
        return ComplexC(ref1.GetReal() * ref2.GetReal(), ref1.GetImage() * ref2.GetImage());
    }
    
    //Operator Overload : /
    ComplexC operator/(ComplexC& ref1, ComplexC& ref2)
    {
        return ComplexC(ref1.GetReal() / ref2.GetReal(), ref1.GetImage() / ref2.GetImage());
    }
    
    int main(void)
    {
        ComplexA C1(2,4), C2(1, 2), C3;
        C3 = C1 + C2; C3.display();
        C3 = C1 - C2; C3.display();
        C3 = C1 * C2; C3.display();
        C3 = C1 / C2; C3.display();
        cout <<"--------------------------------------"<<endl;
        ComplexB C4(2,4), C5(1, 2), C6;
        C6 = C4 + C5; C6.display();
        C6 = C4 - C5; C6.display();
        C6 = C4 * C5; C6.display();
        C6 = C4 / C5; C6.display();
        cout <<"--------------------------------------"<<endl;
        ComplexC C7(2,4), C8(1, 2), C9;
        C9 = C7 + C8; C9.display();
        C9 = C7 - C8; C9.display();
        C9 = C7 * C8; C9.display();
        C9 = C7 / C8; C9.display();
        return 0;
    }
    复制代码

     3、应用举例(对象 ? 基本数据类型 or 基本数据类型 ? 对象)

    上面的例子中是对象 和 对象之间的运算符重载,如果需要一个是对象 + char/int/float/double,或者反过来 char/int/float/double + 对象,这时上面的程序的重载方式就不适用了。

    需要定义新的重载,如下列程序所示。

     

    复制代码
    #include <iostream>
    using namespace std;
    
    class ComplexD
    {
    public:
        ComplexD(double re = 0, double im = 0):real(re),image(im){}
    
        ComplexD operator+(ComplexD& ref){return ComplexD(real+ref.real, image+ref.image);};
        ComplexD operator+(int a){cout<<"IN\t int \t\t";return ComplexD(real+a, image);};
        ComplexD operator+(double d){cout<<"IN\t double \t";return ComplexD(real+d, image);};
        ComplexD operator+(float f){cout<<"IN\t float \t\t";return ComplexD(real+f, image);};
    
        void display(void){cout<<real<<"+"<<image<<"i"<<endl;}
        double GetReal(void){return real;}
        double GetImage(void){return image;}
    private:
        double real;
        double image;
    };
    
    ComplexD operator+(int a, ComplexD& ref){cout<<"OUT\t int \t\t";return ComplexD(ref.GetReal()+a, ref.GetImage());};
    ComplexD operator+(double d, ComplexD& ref){cout<<"OUT\t double \t";return ComplexD(ref.GetReal()+d, ref.GetImage());};
    ComplexD operator+(float f, ComplexD& ref){cout<<"OUT\t float \t\t";return ComplexD(ref.GetReal()+f, ref.GetImage());};
    
    int main(void)
    {
        ComplexD D1(2,4), D2;
        D2 = D1 + 2; D2.display();
        D2 = D1 + 2.1f; D2.display();
        D2 = D1 + 2.1; D2.display();
    
        D2 = 2 +D1; D2.display();
        D2 = 2.1f + D1; D2.display();
        D2 = 2.1 +D1; D2.display();
    
        return 0;
    }
    复制代码

    展开全文
  • 运算符重载

    2020-07-03 21:59:42
    下列关于运算符重载的描述中,错误的是( )。 A 可以通过运算符重载在C++中创建新的运算符 B ... 【答案】A【解析】运算符重载是针对C++中原有运算符进行的,不通过重载创造新的运算符 ...
  • C++运算符重载

    2017-03-24 23:02:21
    C++运算符重载限制重载运算符至少有一个操作数是用户自定义类型重载运算符不违反原运算符的句法规则重载运算符不修改原运算符的优先级不创建新的运算符下列运算符重载 运算符 逻辑操作 sizeof sizeof...
  • C++中不能重载的运算符只有5个: . (成员访问运算符) ...前两个运算符不能重载是为了保证访问成员的功能不能被改变,域运算符和sizeof 运算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征。
  • C++函数调用运算符 () 重载 ...函数调用运算符 () 可以被重载用于类的对象。当重载 () 时,您不是创造了一种新的调用函数的方式,相反地,这是创建一个可以传递任意数目参数的运算符函数。 下面的实例演...
  • 第十一讲:运算符重载与重载函数  * 掌握:算符重载的概念、方法及规则。  * 理解:算符重载作为类成员和友元函数。  重点、难点  * 算符重载的概念、法方及规则。 一、 什么是运算符重载  重载...
  • C++ 重载运算符重载函数

    千次阅读 多人点赞 2019-01-28 10:24:12
    C++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同...
  • C++下标运算符 [] 重载 ...C++ 重载运算符重载函数 下标操作符 [] 通常用于访问数组元素。重载运算符用于增强操作 C++ 数组的功能。 下面的实例演示了如何重载下标运算符 []。 #include &lt;iostre...
  • 运算符 运算符重载 更多内容请查看总目录【Unity】Unity学习笔记目录整理
  • C 运算符中不能重载的有:1、条件运算符“?:”;2、成员访问运算符“.”;3、域运算符“::”;4、长度运算符“sizeof”;5、成员指针访问运算符“->*”和“.*” 。重载...
  • C++中哪些运算符不可重载

    万次阅读 2016-09-07 09:40:30
    几乎所有的运算符都可用作重载。具体包含: 算术运算符:+,-,*,/,%,++,–; 位操作运算符:&,|,~,^,,>> 逻辑运算符:!,&&,||; 比较运算符:<,>,>=,,==,!=; 赋值运算符:=,+=,-=,*=,/=,%=,&=,|=,^=,,>>=; ...
  • 2:运算符重载的目的是:扩展C++中提供的运算符的适用范围,使之作用于对象。 3:运算符重载的实质是函数重载,可以重载为普通函数,也可以重载为成员函数 4:把含运算符的表达式转换成对运算符函数的调用。
  • C# 运算符重载

    2019-10-08 17:50:38
    运算符重载 一提到+ - * / %这种类似的运算符都应该很清楚是什么,但是程序是怎么实现的呢? 程序员也可以使用用户自定义类型的运算符。重载运算符是具有特殊名称的函数,是通过关键字 operator 后跟运算符的符号来...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 14,351
精华内容 5,740
关键字:

下列运算符能被重载的是