本帖最后由 baizy77 于 2018-10-10 17:52 编辑
版权声明------------------------------------------------------------------------------- 作者: 女儿叫老白 (白振勇) 转载请注明出处! ------------------------------------------------------------------------------- -----------------------------------------------------------------------------
引言: ---------------------------------------------------------------------------- 在前面的章节中,我们已经讨论过构造函数的作用与意义,但是我们对于构造函数仍然存在一些疑问,比如 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();
- explicit A2(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 A A:: 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
- void func() {
- 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-()接口。所以对于二元运算符来说,如果希望编译器转换任意一个参数(第一个或第二个),那么就要把操作符定义为友元。 结语: ---------------------------------------------------------------------------- 今天针对运算符重载自问自答了几个问题,其实前两个问题的本质是一样的。我们提这些问题的目的是希望能够加深对运算符重载的理解,希望大家可以在编程中熟练运用这些技能。
|