当前位置: 首页 > 工具软件 > Overload > 使用案例 >

C++实操 - 重载 Overload

宇文嘉勋
2023-12-01

C++作为面向对象语言,其中一个特性就是函数重载(overload)。

在C语言中,如果定义同名函数,以下代码为例:


int func()

{

  return 0;

}



int func(int a)

{

  return 0;

}



int main()

{

  return 0;

}

编译如下:

$ gcc -o test test.c

test.c:9:5: error: redefinition of ‘func’

    9 | int func(int a)

      |     ^~~~

test.c:4:5: note: previous definition of ‘func’ was here

    4 | int func()

      |     ^~~~

提示func这个函数被重复定义,这表明C语言中,函数名是不能重复的。

但上面的代码,用C++来编译:

$ g++ -o test test.cpp

编译通过,没有问题。

所以C++里是可以同名函数的,只要参数列表不同即可,这种机制就叫做函数重载。

有了重载机制可以更灵活的定义函数,将具体调用哪个函数的任务交给编译器,我们只要把功能类似而只是参数不同的函数都使用同一个名字。

除了函数重载,还有运算符重载。指的是,在同一个命名空间内,可以对同样的函数名或操作符名进行多次声明,对每个声明来讲,其使用了不同的函数参数以及拥有不同的定义(实现)。

当调用这种重载的函数或运算符时,根据你使用的函数实参类型和个数,编译器来决定使用最合适的函数定义或操作符定义。

这个编译器判定的过程叫做重载解析,overload resolution。

但要注意的是,只有参数列表可以用来实现函数重载,而返回类型不影响重载。

很明显,函数参数类型信息和个数是调用函数时的输入信息,可以用来判断调用哪个函数合适。

而返回类型是返回执行后的输出信息,没法用来帮助判断应该调用哪个函数。

所以,如果函数名和参数列表相同,只返回值不同,是不能编译通过的。

int func()

{

  return 0;

}



void func()

{

}



int main()

{

  return 0;

}

编译出错:

$ g++ -o test test.cpp

test.cpp:9:6: error: ambiguating new declaration of ‘void func()’

    9 | void func()

      |      ^~~~

test.cpp:4:5: note: old declaration ‘int func()’

    4 | int func()

      |     ^~~~

-----------------------------  

C++中的子类和父类,其内部定义的函数独立的,父类里定义的成员函数不会影响到子类。


class A{



public:

  int funcA(){return 0;}

  int funcA(int a){return 0;}



// 在同一个类里,仅返回类型不同的函数不能同时定义

//  void funcA(){}

};





class B:public A{

public:

  // 父类和子类的成员函数定义不会冲突

  void funcA(){}



};



int main()

{

  return 0;

}

上面的代码能正常编译通过。

$ g++ -o test test.cpp

但如果使用虚函数的话,子类和父类的同名和同参数列表的函数,就会产生关联,要保证返回类型也一样才行。


class A{



public:

  virtual int funcA(){return 0;}

  int funcA(int a){return 0;}

};



class B:public A{

public:

  void funcA(){}

};



int main()

{

  return 0;

}





$ g++ -o test test.cpp

test.cpp:16:8: error: conflicting return type specified for ‘virtual void B::funcA()’

   16 |   void funcA(){}

      |        ^~~~~

test.cpp:9:15: note: overridden function is ‘virtual int A::funcA()’

    9 |   virtual int funcA(){return 0;}

      |               ^~~~~

上面的无参数的funcA成员函数,在父类和子类中都定义了,并且是虚函数,但返回值类型不同,所以就报错。

-------------------- 

关于操作符重载,

你可以重新定义或重载C++中的大多数内置运算符。因此,程序员也可以使用用户定义的类型的运算符。

重载运算符是具有特殊名称的函数:关键字 "operator",后面是所定义的运算符的符号。像其他函数一样,重载运算符有一个返回类型和一个参数列表。

比如:

Box operator+(const Box&);

上面例子声明了加法运算符,可用于对两个盒子对象执行加运算并返回最终的盒子对象。大多数重载运算符可以被定义为普通的非成员函数或类成员函数。如果我们将上述函数定义为一个类的非成员函数,那么我们必须传递两个实参,每个操作数一个参数,如下所示:

Box operator+(const Box&, const Box&);

具体的操作符重载的实现的例子,使用类成员函数来实现:

Box operator+(const Box& b) {

         Box box;

         box.length = this->length + b.length;

         box.breadth = this->breadth + b.breadth;

         box.height = this->height + b.height;

         return box;

      }

可以重载的操作符如下:

+

-

*

/

%

^

&

|

~

!

,

=

<

>

<=

>=

++

--

<<

>>

==

!=

&&

||

+=

-=

/=

%=

^=

&=

|=

*=

<<=

>>=

[]

()

->

->*

new

new []

delete

delete []

不可以重载的操作符:

C操作符:

.           //  成员访问或点操作符Member access or dot operator

?:         // 三元条件操作符 Ternary or conditional operator

sizeof  // 对象大小计算操作符  The object size operator

C++操作符:

::     // 域访问操作符 Scope resolution operator

.*    // 成员指针操作符 Pointer to member operator

sizeof运算符返回作为操作数(对象或数据类型)的大小。这是由编译器计算的,它在运行时不能被计算。所以我们不能重载它。

参考:

C++ Overloading (Operator and Function)

13.5 — Overloading operators using member functions – Learn C++

 类似资料: