baizy77 发表于 2018-10-10 17:33:35

C++老鸟日记038 运算符重载之二三问

本帖最后由 baizy77 于 2018-10-10 17:52 编辑

版权声明-------------------------------------------------------------------------------该文章原创于Qter开源社区(www.qter.org)作者: 女儿叫老白 (白振勇)转载请注明出处!-------------------------------------------------------------------------------课程目录:《C++老鸟日记》目录本套课程属于:《C++跨平台开发干货》系列课程。-----------------------------------------------------------------------------

引言:----------------------------------------------------------------------------       在前面的章节中,我们已经讨论过构造函数的作用与意义,但是我们对于构造函数仍然存在一些疑问,比如1,类A的构造函数的参数一定是类A吗?2,构造函数自动类型转换指什么?怎样防止构造函数自动类型转换?3,如果想让二元运算符转换任一个参数,需要怎么做?下面我们依次解答。
正文:----------------------------------------------------------------------------       闲话少说,直接看题。问题1,类A的构造函数的参数一定是类A吗?代码清单:----------------------------------------------------------------------------
// a.h
class A {
public:
       A();
       A(const A& a);
};
----------------------------------------------------------------------------
在上述代码中,类A的构造函数是一个A类型的const引用,这同我们之前看到的构造函数一样,但是也不总是这样。请看下面的代码:代码清单:----------------------------------------------------------------------------
// f.h
class F {
public:
       F();
};
// a2.h
class A2 {
public:
       A2();
       A2(const F&f);
};
----------------------------------------------------------------------------
从上述代码可以看出,类A2提供了一个不一样的构造函数,它传入一个F类型的const引用,这可以用来将F类型的对象转换为A类型的对象。在前面的章节中,我们也提到过这种编程方法。在这个构造函数中,只要把F类型对象的成员数据根据需要对应拷贝到A的对象上就可以了。
问题 2,构造函数自动类型转换指什么?怎样防止构造函数自动类型转换?       其实这个问题同前面的问题性质一样。代码清单:----------------------------------------------------------------------------
void func(A);
……
int main(int argc, char*argv[]) {
       F f;
       func(f);
}
----------------------------------------------------------------------------
       从上述代码可以看出,函数func()的入口参数类型为A,但是main()函数中调用func()函数时传入的参数的类型为F,因为上一个问题中类型A提供了拷贝构造函数:       A(const F& f);       所以,对于func(f)这行代码,编译器检查到这个函数需要一个类型为A的对象,编译器会检查是否有从类型F转换为类型A的方法,结果编译器找到了构造函数A(const F&),因此编译器悄悄执行隐式类型转换,将f转换为类型A。这称作构造函数的自动类型转换。       有时候通过构造函数自动类型转换可能会出现问题,那么,怎样防止这种情况呢?通过声明显示构造函数来解决:
代码清单:----------------------------------------------------------------------------
// a2.h
class A2 {
public:
       A2();
       explicitA2(const F&f);
};
----------------------------------------------------------------------------
       关键字explicit通知编译器,必须使用显示类型转换,也就是说下面的代码不起作用了:    代码清单:----------------------------------------------------------------------------
void func(A);
……
int main(int argc, char*argv[]) {
       F f;
       func(f); // 编译错误:不允许自动类型转换
}
----------------------------------------------------------------------------
       上面的代码会导致编译错误:不允许自动(隐式)类型转换。如果仍然希望调用func,代码应做如下改动:代码清单:----------------------------------------------------------------------------
void func(A);
……
int main(int argc, char*argv[]) {
       F f;
       func(A(f));
}
----------------------------------------------------------------------------

场景3,如果想让二元运算符转换任一个参数,需要怎么做?这个问题是啥意思呢?我们都知道使用成员函数方式重载+-*/这些操作符时,仅仅提供一个入口参数就够了,也就是说,编译器只能尝试把第二个参数进行自动类型转换,那么如果希望编译器自动将任意一个参数(不管第一个还是第二个)进行隐式类型转换,该怎么做呢?
代码清单:----------------------------------------------------------------------------
// a.h
class A {
public:
       A(int i) {m_i = i;}
       const A operator+(const A&) const;
       int getI(){return m_i;}
       friend const A operator-(const A&, const A&);
private:
       m_i;
};

// a.cpp
const AA:: operator+(const A& right)const {
returnA(m_i + right.getI());
}
const A operator-(constA& a1, const A& a2) {
       return A(a1.m_i – a2.m_i);
}

// main.cpp
voidfunc() {
       A a(3);
       a + 5;
       2 – a;
}
----------------------------------------------------------------------------
在上述代码中,类A拥有重载的成员运算操作符operator+()和友元操作符operator-()。因为A有一个int参数的构造函数,所以int可以隐式(自动)转换为类型A。所以,当编译器看到 a+5时,编译器会查看A的重载操作符中有没有operator+()接口,当它找到后会自动把第二个操作数5转换为A类型对象并调用a的operator+()接口。但是当编译器看到2-a时就不同了,编译器会把第一个操作数2转换为类型A,因为A有友元操作符operator-()接口。所以对于二元运算符来说,如果希望编译器转换任意一个参数(第一个或第二个),那么就要把操作符定义为友元。结语:----------------------------------------------------------------------------       今天针对运算符重载自问自答了几个问题,其实前两个问题的本质是一样的。我们提这些问题的目的是希望能够加深对运算符重载的理解,希望大家可以在编程中熟练运用这些技能。
页: [1]
查看完整版本: C++老鸟日记038 运算符重载之二三问