知了博客

集天地之精华,吸日月之灵气

« 口苦原因及治疗CWND *this »

c++操作符重载

c++有许多内置数据类型,包括int,char,double, 第一种类型有许多运算符,比如,+ - * /.当用户定义了许多类对象时,对像间是不能进行这些操作的.但c++类允许把这些运算符内置到c++类中,可以像操作内置对象一样操作.

 

来源:csdn

1)前缀式操作符返回被增量或减量对象的引用。后缀返回的是值返回。
2)前缀和后缀操作符的区别:后缀操作符函数接受一个额外的int,使用时,编译器自动提供0为实参。
3)前缀和后缀互相利用。还有很多也是这样:+/+=,>/<都是这样。
4)自增自减定义为类成员。很多操作改变操作对象的状态,则将它们做为成员。

class A

{

public:

A operator ++(int)

{ A temp = *this;

++ nData;

return temp;

}

A operator ++(int)

{

++ nData;

return *this;

}

}

main()

{

A a,b;

// 后置操作

a++;

a.operator ++(0);

// 前置操作

++b;

b.operator ++();

}

 5 //总结:重载操作符可以写成成员函数和友员函数。成员函数是类内部的
  6 //函数,而友员函数是外部的函数,例如全局函数,甚至其他类里面的函数,我的习惯是
  7 //写成成员函数,因为我觉得这样感觉要好一点,而且在成员函数中参数还可以少一个。
  8 //哈哈,不过问题就是他不能重载左二元操作符(符号在他的左边),也就是操作符是在他的左边,所以在
  9 //重载一个整数和这个类相加的情况就只能写友员函数了。
 10 //重载操作符的参数个数一定要跟默认参数个数的一样,除了()这样的可以自己定义以外,
 11 //例如operator+();这是错误的,还有operator(int a, int b,int c);这也是错误的
 12 //我下面之所以只有一个,是因为他是成员函数。自己已经包括在里面了,而友员就必须两个都写。
 13 //重载的返回类型没有规定,C++也不是用返回来判断是否重载的,
 14 //他是根据函数名和参数列表来判断的。成员函数加const也是重载的一种,但是如果其他都一样只有
 15 //返回类型不一致,就认为是错误的重载。例如:
 16 //int operator+(int nAdd) const;和
 17 //CBaseOperator operator+(const CBaseOperator& cAdd) const;就会认为是错误的重载
 18 //而int operator+(int nAdd) const;和int operator+(int nAdd);就是正确的,他们是两个不同的函数
 19 //在调用上,在未指明为const的类调用时,使用的是非const的函数。如果没有非const的函数,
 20 //他才会调用const的函数。而如果const的类去调用非const的函数,会直接报错。所以
 21 //在写代码时,可以考虑是不是可能会修改成员,如果希望是不修改的,那么请用const,这样强制性的
 22 //会提高你的编码能力的。(扯远了,呵呵。)
 23 //都说友员是一个强大的东东,可以访问内部的private函数和变量,但是,如果把拷贝构造函数和
 24 //=重载为私有的话,他是不能访问的。。哈哈。设计语言的人真厉害。。
 25
 26 //百度百科找的资料:
 27 //什么时候定义类成员操作符重载,什么时候定义非类成员操作符重载?
 28 //答:(1)如果一个重载操作符是类成员,那么只有当跟它一起使用的左操作数是该类对象时,
 29 //它才会被调用,如果该操作符的左操作数必须是其他类型,那么重载操作符必须是非类成员操作符重载。
 30 //(2)C++要求,赋值(=),下标([ ]),调用(())和成员访问箭头(->)操作符必须被指定为类成员操作符,否则错误。
 31
 32 //http://www.examda.com/ncre2/cpp/fudao/20080312/092830274-2.html 网站的资料
 33 //不能重载的操作符号:
 34 //. .* :: ?: new delete sizeof typeid static_cast dynamic_cast const_cast reintERPret_cast
 35 //可以重载的操作符:
 36 //operator new operator delete operator new[] operator delete[]
 37 // + - * / % ^ & | ~ ! = < > += -= *= /= %=  ^= &= |= << >> >>= <<= == !=
 38 // <= >= && || ++ -- , ->* -> () []
 39 //貌似这里可以重载new
 40
 41 //重载简单的+-*/%等
 42 class CBaseOperator
 43 {
 44
 45 public:
 46     int nData;        //测试的变量
 47
 48 public:
 49     CBaseOperator(int nData = 0):nData(nData)
 50     {
 51         nData++;
 52         --nData;
 53     }
 54
 55    
 56     CBaseOperator(const CBaseOperator& cBO)
 57     {
 58         nData = cBO.nData;
 59     }
 60     //重载=操作符,一般=操作符和拷贝构造函数是成对出现的。
 61     const CBaseOperator& operator=(const CBaseOperator& cBO)
 62     {
 63         nData = cBO.nData;
 64         return *this;
 65     }
 66
 67 public:
 68
 69     //重载+操作符,简单的二元操作符重载是最常见也是比较简单的。基本思路都是这样,注意如果
 70     //操作符出现在左边,则只能用友员了。这里了有几个返回类型是CBaseOperator,return
 71     //语句中却是两个int相加,这种情况是可以通过的,编译器会自动构建一个相应的对象返回,
 72     //前提是你的构造函数要有相应的参数,这里是int作为参数
 73     int operator+(int nAdd) const
 74     {
 75         return nData + nAdd;
 76     }
 77
 78     int operator+(int nAdd)
 79     {
 80         return nData + nAdd;
 81     }
 82    
 83     friend int operator+(int nAdd,const CBaseOperator& cAdd)
 84     {
 85         return nAdd + cAdd.nData;
 86     }
 87    
 88     CBaseOperator operator+(const CBaseOperator& cAdd) const
 89     {
 90         return nData + cAdd.nData;
 91     }
 92
 93     //重载减法什么的也是一样。就不写了。哈哈
 94
 95     //比较操作符重载==,!=,>, >=, <, <=总结:这里都是配套的操作一般来说如果写一个
 96     //都会重载其他几个,特别是==,!=。当然也有例外。哈哈。。
 97     bool operator==(const CBaseOperator& cEqual) const
 98     {
 99         return nData == cEqual.nData;
100     }
101     bool operator == (int nEqual) const
102     {
103         return nData == nEqual;
104     }
105     friend bool operator ==(int nEqual, const CBaseOperator& cEqual)
106     {
107         return cEqual.nData == nEqual;
108     }
109     bool operator!=(const CBaseOperator& cEqual) const
110     {
111         return nData != cEqual.nData;
112     }
113
114     //其他的也就不写了,基本一样。哈哈
115
116     //重载++,--操作符,因为++,--有两种方式,一种是前增量(++XXX先改变自己,返回),
117     //一种是后增量(改变自己,返回改变前的状态)
118     //因为重载是判断参数的,为了能区别前增量和后增量,C++的设计者做了这样的考虑。
119     //就是重载后增量的时候在参数列表中加一个int类型参数,这样就避免的重载的重复了。
120     //在调用上,如果都重载,那么用int参数的是后增量++,没有参数的是前增量++,
121     //(注:这里说的是成员函数,当然友员的重载参数个数要多一个,以后的我可别说我无知啊。)
122     //如果都重载,则前增量和后增量都会调用相应的函数,如果只重载了后增量,那么前增量会失败
123     //如果只重载了前增量,就会无论是前增量和后增量都会调用这个函数。所以一般他们也是成对
124     //出现的,除非你懒,只写前增量,可惜如果人家要调用后增量呢?结果会错的哦。哈哈。
125
126     //重载后增量.
127     CBaseOperator operator++(int)
128     {
129         CBaseOperator cTemp = *this;
130         ++nData;
131         return cTemp;
132     }
133
134     //重载前增量
135     CBaseOperator& operator++()
136     {
137         ++nData;
138         return *this;
139     }
140
141     //重载--操作符是一样的,也不写了。
142
143     //重载[],()等操作符号,同样[]的参数个数是确定的。
144     //我之说以把他们写一起,是因为我错误的以为[]的参数个数是可以自己定义。错了错了。
145     //知错能改是好的,对了,()的参数个数是可以自己定义的。这个就给我们很大的发挥空间了。
146     //都忘了[],() = 等操作符必须是成员函数,上面有写。不能用友员和静态成员函数
147
148     //重载[]
149     int operator[](int nIndex) const
150     {
151         return nIndex;
152     }
153
154     //重载()
155     int operator()(int a) const
156     {
157         return a;
158     }
159
160     bool operator()(int a, int b) const
161     {
162         return a > b;
163     }
164
165     CBaseOperator operator()(int a, int b, int c)
166     {
167         return CBaseOperator(a+b+c+*this);
168     }
169
170     //重载*,->的操作符,*操作符就是相当于指针的*p;但这里已失去了原来的意义,不是指针了。
171     //如果想通过他来得到一些东西,也是可以的,特别在迭代器中常用这种方法。->也是和*配对出现的。
172     //不过->操作符比较有意思,貌似和(*p).dddd真的差不多,所以返回的应该是一个结构的指针,
173     //我们这里就返回了本身,当然可以返回任何结构的指针的。(并不是只能返回本身)。
174
175     //重载*,这里参数个数是固定的,多写一个就成了乘法的操作了。哈哈
176     int operator*() const
177     {
178         return nData;
179     }
180
181     //重载->
182     CBaseOperator* operator->()
183     {
184         return this;
185     }
186
187     //其他的例如&& || 这样的操作符还是不重载的好。利用其原有的本性
188
189     //重载new delete,这里编译器做了一个限制,new必须返回void*类型, delete必须
190     //返回void类型。(上面说过函数重载是不检查返回类型的,和这里并没有冲突,他只是限定了返回
191     //类型,而不是只有返回类型不同的函数能重载,这个是编译器做的工作,一定上确保new能更好的工作吧)
192     //还有就是他们的参数个数都是可以自定义的。new 和 new[] 是两个不同的操作符,所以还是要分别重载一下。
193     //delete 和 delete[] 也是两个不同的操作符。这里只重载了一个。
194     void* operator new(size_t size)
195     {
196        
197         return  malloc(size);
198     }
199
200     void* operator new[](size_t size)
201     {
202         return  malloc(size);
203     }
204
205     void operator delete(void* P, unsigned int size)
206     {
207         size = 0;
208         free(P);
209     }
210 };
211
212 int main()
213 {
214     const CBaseOperator cCo1(100);
215
216     //判断+重载符
217     int nSum = cCo1 + 50;
218     printf("%d\n", nSum);
219     nSum = 50 + cCo1;
220     printf("%d\n", nSum);
221
222     //这里顺便检测一下拷贝构造函数
223     CBaseOperator co2(20);
224     CBaseOperator co3 = co2 + cCo1;
225     nSum = co3.nData;
226     printf("%d\n", nSum);
227
228     nSum = co3 + 60;
229     printf("%d\n", nSum);
230
231     //检测+,和=操作符
232     co3 = 10 + cCo1 + co2 + 20;
233     nSum = co3.nData;
234     printf("%d\n", nSum);
235
236     //查看比较操作符
237     if (cCo1 == cCo1 && cCo1 == 100 && 100 == cCo1)
238     {
239         printf("True\n");
240     }
241     co3 = co2;
242     if (!(co3 != co2))
243     {
244         printf("True\n");
245     }
246
247     //增量操作符,cCo1是不能做这个操作的,因为他是常量
248     nSum = co2.nData;
249     printf("%d\n", nSum);
250     nSum = (co2++).nData;
251     printf("%d\n", nSum);
252     nSum = (++co2).nData;
253     printf("%d\n", nSum);
254
255     //测试[],
256     nSum = cCo1[45];
257     printf("%d\n", nSum);
258
259     //测试()
260     nSum = cCo1(50);
261     printf("%d\n", nSum);
262    
263     if (cCo1(45, 23))
264     {
265         printf("True\n");
266     }
267
268     co2 = co3(10,20,30);
269     nSum = co2.nData;
270     printf("%d\n", nSum);
271
272     //测试*,这里co2并不是指针哦。只是重载了*的操作符
273     nSum = *co2;
274     printf("%d\n", nSum);
275
276     //测试->,这里也一样。
277     nSum = co2->nData;
278     printf("%d\n", nSum);
279
280     //测试new new[] delete,
281     //这里没有测试输出。单步就知道了。
282     CBaseOperator* pCb1 = new CBaseOperator();
283     CBaseOperator* pCb2 = new CBaseOperator[10];
284     delete pCb1;
285     delete pCb2;
286
287     system("pause");
288     return 0;
289 }
290

赋值操作符

赋值操作符即“=”。赋值操作符为二元操作数,其操作目的是将右操作数的值复制给左操作数。由于左值涉及到写操作,因此左值必须为非const量,而右值在赋值操作中只涉及读操作,因此一般为const量。

赋值操作符通常返回左操作数的引用,这样就不需要创建和撤销运算结果的临时副本。

C/C++编译器支持对内置类型(例如整形int和浮点型double)的赋值运算。

字符数组(字符串)的赋值

对于const变量进行赋值是非法的,例如数组名为不可修改的左值。

    char cstr1[6] = "cstr1";

    char cstr2[6] = "cstr2";

    cstr1 = cstr2; // error C2106: '=' : left operand must be l-value

对于内置类型数组的赋值需要逐个元素进行赋值。对于以上C字符串类型,<string.h>中定义了标准库函数char* strcpy(char *dst, const char *src);用于字符串的赋值。其实现如下:

// strcat.c

char * __cdecl strcpy(char * dst, const char * src)

{

        char * cp = dst;

        while( *cp++ = *src++ );   /* Copy src over dst */

 

        return( dst );

}

对于非内置类型,如自定义的复数类型complex,我们必须重载赋值操作符“=”,使其支持complex对象之间的赋值。

// complex

    _Myt& operator=(const _Myt& _Right)

    {   // assign other complex

       this->_Val[0] = _Right.real();

       this->_Val[1] = _Right.imag();

       return (*this);

    }

C++标准库string类型封装了C字符串类型的操作,它重载了赋值操作符,但其内部实现同strcpy,也是逐个字符进行(迭代)赋值。

例解CString::operator =

MFC中的字符串处理类CString中对赋值操作符“=”做了多个版本的重载,这样CStirng不仅支持同类对象的赋值,还支持将字符类型(TCHAR)、以及C字符串类型(LPCTSTRunsigned char*)赋值给CString对象。

// AFX.H

class CString

{

public:

// ……

    // ref-counted copy from another CString

    const CString& operator=(const CString& stringSrc);

    // set string content to single character

    const CString& operator=(TCHAR ch);

#ifdef _UNICODE

    const CString& operator=(char ch);

#endif

    // copy string content from ANSI string (converts to TCHAR)

    const CString& operator=(LPCSTR lpsz);

    // copy string content from UNICODE string (converts to TCHAR)

    const CString& operator=(LPCWSTR lpsz);

    // copy string content from unsigned chars

    const CString& operator=(const unsigned char* psz);

// ……

}

上述返回值的类型为const CString&,即返回指向const CString对象的引用,返回被赋值对象的引用(return *this;),而加const修饰则说明不允许对返回值进行写操作。

    CString afxstr1 = "afxstr1";

    CString afxstr2 = "afxstr2";

    CString afxStr3 = afxstr2 = afxstr1; // afxStr3 = (afxstr2 = afxstr1);

    (afxStr3 = afxstr2) = afxstr1; // error

上述代码中afxstr2 = afxstr1调用const CString& CString::operator=(const CString& stringSrc) afxstr1的值赋给afxstr2(AssignCopy)。形如CString::operator=(&afxstr2, afxstr1),其中第一个参数为具体CString对象的this指针。注意CString afxStr3 = afxstr2中的“=”赋值运算符将隐式创建对象,调用构造函数CString::CString(const CString& stringSrc)C++中的explicit关键字用来修饰类的构造函数,以限制这种隐式转换构造。

(afxStr3 = afxstr2) = afxstr1;试图对赋值操作返回值进行二次赋值是不允许的,因为赋值操作返回值受const限定,不可再作为赋值运算的左值。

类的赋值牵涉到深拷贝和浅拷贝问题,牵涉到拷贝构造函数。CString中的引用计数CStringData::nRefs用来实现在线拷贝(浅拷贝),从而提高内存管理和操作的效率。

    CString afxstr1 = "afxstr1"; // CString::CString(LPCTSTR lpsz);

    CString afxstr2 = "afxstr2"; // CString::CString(LPCTSTR lpsz);

    CString afxstr3 = afxstr1;   // CString::CString(const CString& stringSrc)

    afxstr3 = afxstr2; // const CString& CString::operator=(const CString& stringSrc)

上述代码中afxstr3 = afxstr2;只是简单的做afxstr3.m_pchData = afxstr2..m_pchData;的指针赋值操作,即just copy references around

 

算术操作符

+-*/%是常用的运算操作符,其用法为expr1+expr2expr1-expr2expr1*expr2expr1/expr2expr1%expr2。它们皆为二元操作符,即它们作用于两个操作数,其中expr1为左操作数,expr2为右操作数。运算结果为同类操作数(对象),一般使用赋值操作符对运算结果进行接收,形如res= expr1+expr2

+=-=*=/=%=”等为复合赋值运算符,它表示把右边的表达式加到左边的操作数的当前值上,因此左操作数又充当了运算结果的接收者。其调用形式与赋值操作符相同,如expr1+=expr2,实际操作为expr1=expr1+expr2。鉴于左操作数既做操作数又做返回值接收器,因此复合赋值运算符通常也返回左操作数的引用。

C/C++编译器支持对内置类型(例如整形int和浮点型double)的算术运算。

    // <1>基本内置类型

    int n1 = 2010;

    int n2 = 2;

    int n3 = n1+n2; // OK. n3 is the sum of n1 and n2.

字符串的+连接操作

我们使用+运算符企图连接两个字符串是错误的,因为C/C++编译器对于字符串类型(char[])没有提供内置的衔接操作。因此,我们必须重载“+”运算符实现期望的操作。<string.h>中定义了标准库函数char* strcat(char *dst, const char *src);用于字符串的连接。

// strcat.c

char * __cdecl strcat (char * dst, const char * src)

{

        char * cp = dst;

 

        while( *cp )

                cp++;                   /* find end of dst */

 

        while( *cp++ = *src++ ) ;       /* Copy src to end of dst */

 

        return( dst );                  /* return dst */

}

    // <2>(字符)数组类型

    char cstr1[6] = "cstr1";

    char cstr2[6] = "cstr2";

    char cstr3[12] = {0};

    cstr3 = cstr1+cstr2; // error C2110: cannot add two pointers

    strcat(cstr3, cstr1);

    strcat(cstr3, cstr2);

C++标准库string类型重载了“++=”操作符,但其内部实现同strcat

例解CString::operator +(=)

MFC中的字符串处理类CString中对赋值操作符“++=”做了多个版本的重载,这样CStirng不仅支持同类对象的连接,还支持将字符类型(TCHAR)、以及C字符串类型(LPCTSTR)连接到CString对象上。

// AFX.H

class CString

{

public:

// ……

    // concatenate from another CString

    const CString& operator+=(const CString& string);

 

    // concatenate a single character

    const CString& operator+=(TCHAR ch);

#ifdef _UNICODE

    // concatenate an ANSI character after converting it to TCHAR

    const CString& operator+=(char ch);

#endif

    // concatenate a UNICODE character after converting it to TCHAR

    const CString& operator+=(LPCTSTR lpsz);

 

    friend CString AFXAPI operator+(const CString& string1, const CString& string2)

{

// STRCOR.CPP

    CString s; // temporary object for concat result

    s.ConcatCopy(string1.GetData()->nDataLength, string1.m_pchData,

       string2.GetData()->nDataLength, string2.m_pchData);

    return s;

}

 

    friend CString AFXAPI operator+(const CString& string, TCHAR ch);

    friend CString AFXAPI operator+(TCHAR ch, const CString& string);

#ifdef _UNICODE

    friend CString AFXAPI operator+(const CString& string, char ch);

    friend CString AFXAPI operator+(char ch, const CString& string);

#endif

    friend CString AFXAPI operator+(const CString& string, LPCTSTR lpsz);

    friend CString AFXAPI operator+(LPCTSTR lpsz, const CString& string);

// ……

}

由于operator+是对两个CString相关的对象的连接操作,不属单对象操作,因此它们应是全局函数(AFXAPI),被设置为CString的友元成员(函数)。而CString对象作为操作数不涉及写访问,因此一般定义const常量;而为避免副本带来的内存开销,一般传入引用,即const CString& string。当然,对于内置类型TCHAR作为操作数,一般不考虑副本内存开销的问题。

    CString afxstr1 = "afxstr1";

    CString afxstr2 = "afxstr2";

    CString afxstr3 = afxstr1+afxstr2;

上述代码中afxstr3 = afxstr1+afxstr2;调用CString operator+(const CString& string1, const CString& string2),即operator+(afxstr1, afxstr2),“afxstr3 =”将存放afxstr1+afxstr2结果的临时对象s拷贝给afxstr3

另外,可参考MFCCPointCSizeCRect之间的运算操作。

 

下标操作符

可以从容器中检索单个元素的容器类一般会定义下标操作符,即 operator[]C/C++编译器定义了对内置类型数组的下标访问。标准库的类 string vector 均定义了下标操作符。

定义下标操作符比较复杂的地方在于,它在用作赋值的左右操作符数时都应该能表现正常。下标操作符出现在左边,必须生成左值,可以指定引用作为返回类型而得到左值。只要下标操作符返回引用,就可用作赋值的任意一方。

下标操作符必须定义为类成员函数,一般需要定义两个版本:一个为非 const 成员并返回引用,另一个为 const 成员并返回 const 引用。

例解一:CString::operator[]

MFC封装的是对C字符串的操作,因此提供了operator[],以对内部字符缓冲区((LPTSTR m_pchData)char[]索引访问(读和写)。

class CString

{

public:

// ……

    // return single character at zero-based index

TCHAR operator[](int nIndex) const { return m_pchData[nIndex]; }

// ……

}

例解二:CArray::operator[]

MFC中的数组集合类CArray operator[]的重载为普通的数组索引访问。

// AFXTEMPL.H

template<class TYPE, class ARG_TYPE>

class CArray : public CObject

{

public:

// ……

    // overloaded operator helpers

    TYPE operator[](int nIndex) const { return GetAt(nIndex); }

    TYPE& operator[](int nIndex) { return ElementAt(nIndex); }

// ……

}

    注意上述CArray::operator[]两个版本的区别在于第一个版本后面的const修饰传递给该函数的this指针,即const对象调用operator[]的第一个版本(传入const CArray* const this指针),非const对象调用operator[]的第二个版本(传入CArray* const this指针)。

如果只定义了第一个版本,没有定义第二个版本,非const对象调用operator[]实际上对传入的非const指针进行了const隐式转换。

例解三:CMap::operator[]

字典映射类CMapoperator[]的重载是哈希查找。实现由key查找value的“索引”访问,同时又可对索引返回值进行赋值(形如map[key] = value,先GetSet)。

template<class KEY, class ARG_KEY, class VALUE, class ARG_VALUE>

class CMap : public CObject

{

// ……

    // Lookup and add if not there

    VALUE& operator[](ARG_KEY key);

// ……

}

 

类型转换符

在对内置类型进行二元运算时,如果两个操作数类型不一致,编译器会进行隐式转换。

       int n = 0;

n = 3.541 + 3; // warning C4244: '=' : conversion from 'const double' to 'int', possible loss of data

以上代码n = 3.541 + 3在编译时检查到该表达式需进行类型转换,将给出doubleint截断转换的精度损失警告,其在运行期等效于n = (int)((double)3.541+(double)3);这个是编译器对内置类型的自动隐式转换支持。

例解一:CString::operator LPCTSTR

我们在对字符串进行处理的时候,难免会遭遇char*char[])与stringCString的混合处理问题。例如我们可能需要将char字符数组(C字符串)拷贝给CString对象,或将CString对象的值拷贝到char字符数组(C字符串)中。

    char cstr[16] = "c string";

CString afxstr = "CString";

strcpy(cstr, afxstr); // right

printf("afxstr = %s", afxstr); // right

strcpy(afxstr, cstr); // error

strcpy((char*)(LPCTSTR)afxstr, cstr); // right

afxstr = cstr; // invoke const CString& CString::operator=(&afxstr, LPCSTR lpsz);

代码strcpy(cstr, afxstr)printf("afxstr = %s", afxstr)运行时,将试图对CString对象afxstr做向const char*的转换(const char*)(afxstr)以满足形参二的预期类型。在非UNICODE环境下,const *charLPCTSTR,因此这里将调用CString提供的LPCTSTR转换符,形如CString::operator LPCTSTR(&afxstr),其中&afxstr即为对象的this指针,返回CString对象afxstr内部指向缓冲区的常量指针:this->m_pchData

代码strcpy(afxstr, cstr);是错误的,因为对CString对象的引用无法直接对其数据区(LPTSTR m_pchData;)进行写访问的,不存在这种转换支持。但若我们对afxstr进行强制char*cosnt转换(C++中的const_cast) ,即strcpy((char*)(LPCTSTR)afxstr, cstr);编译运行都正确。但一般不提倡这么做,获取CString内部指向缓冲区的非常量指针(LPTSTR m_pchData;)的安全做法是调用CStringGetBuffer()方法。

实际上,CString类重载的operator=赋值运算符,具体为const CString& operator=(LPCSTR lpsz)支持将char字符数组(C字符串)直接对CString对象进行赋值,直接afxstr = cstr;即可。

// AFX.H

class CString

{

public:

// ……

    // return pointer to const string

    operator LPCTSTR() const { return m_pchData; }

 

    // get pointer to modifiable buffer at least as long as nMinBufLength

    LPTSTR GetBuffer(int nMinBufLength);

// ……

}

例解二:CTypeSimpleList::operator TYPE

MFC线程局部存储中使用到的简单模板链表CTypedSimpleListTYPE()操作符,使得链表支持直接引用对象,以返回链表首节点。

// AFXTLS_.H

template<class TYPE>

class CTypedSimpleList : public CSimpleList

{

public:

// ……

    operator TYPE()

       { return (TYPE)CSimpleList::GetHead(); }

};

下列代码片段演示了CTypedSimpleList的使用。

    MyThreadData* pData;

    CTypedSimpleList<MyThreadData*> list;

    list.Construct(offsetof(MyThreadData, pNext));

 

    // 向链表中添加成员

    for(int i=0; i<10; i++)

    {

       pData = new MyThreadData;

       pData->nSomeData = i;

       list.AddHead(pData);

    }

 

    // …………   // 使用链表中的数据

 

    // 遍历整个链表,释放MyThreadData对象占用的空间

    pData = list;  // 调用了成员函数 operator TYPE(),相当于“pData = list.GetHead();”语句

    while(pData != NULL)

    {

// ……

    }

上面代码中pData = list;赋值语句中,左值为数据类型,右值为链表类型,对右值进行隐式类型转换才能实现赋值:pData = (MyThreadData*)(list);编译时检查有无此转换支持(即检查CTypedSimpleList 是否存在TYPE()转换符操作支持)。其中MyThreadData*TYPE,因此运行期调用CTypedSimpleListoperator TYPE()转换符,即CTypedSimpleList::TYPE(&list)àlist.GetHead(),返回链表的首节点。

例解三:CWnd::operator HWND; CAsyncSocket::operator SOCKET;

MFC中封装某种内核对象的类一般都支持对其内核对象做类型转换,典型的如CWndàHWND

class CWnd : public CCmdTarget

{

// ……

// Attributes

public:

    HWND m_hWnd; // must be first data member

    operator HWND() const;

// ……

}

CWnd只不过封装了窗口对象HWND的操作,因此在调用需要HWND参数的API时,也可直接传入CWnd对象。

类似的还有CAsyncSocketàSOCKET

class CAsyncSocket : public CObject

{

// ……

// Attributes

public:

    SOCKET m_hSocket;

    operator SOCKET() const;

// ……

}

 

关系操作符

    关系操作符主要指同类对象的值大小比较,包括等于(==)、大于(>)、小于(<)等。关系操作符与算术操作符一样都是二元操作符,不过关系操作符返回的是布尔值。

 

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

日历

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Arwen Build 90619 Code detection by Codefense  theme by BokeZhuti

Copyright know blog. Some Rights Reserved.站长(msn):webmaster#webgou.info(#换成@) 粤ICP备09183716号