C++批评系列:函数重载

原创 2005年03月04日 15:20:00
C++批评系列:函数重载
Ian Joyner
cber译
译者前言:要想彻底的掌握一种语言,不但需要知道它的长处有哪些,而且需要知道它的不足之处又有哪些。这样我们才能用好这门语言,避免踏入语言中的一些陷阱,更好地利用这门语言来为我们的工作所服务。Ian Joyner的这篇文章以及他所著的Objects Inencapsulated一书中,向我们充分的展示了C++的一些不足之处,我们应该充分借鉴于他已经完成的伟大工作,更好的了解C++,从而写出更加安全的C++代码来。
C++允许在参数类型不同的前提下重载函数。重载的函数与具有多态性的函数(即虚函数)不同处在于:调用正确的被重载函数实体是在编译期间就被决定了的;而对于具有多态性的函数来说,是通过运行期间的动态绑定来调用我们想调用的那个函数实体。多态性是通过重定义(或重写)这种方式达成的。请不要被重载(overloading)和重写(overriding)所迷惑。重载是发生在两个或者是更多的函数具有相同的名字的情况下。区分它们的办法是通过检测它们的参数个数或者类型来实现的。重载与CLOS中的多重分发(multiple dispatching)不同,对于参数的多重分发是在运行期间多态完成的。
【Reade 89】中指出了重载与多态之间的不同。重载意味着在相同的上下文中使用相同的名字代替出不同的函数实体(它们之间具有完全不同的定义和参数类型)。多态则只具有一个定义体,并且所有的类型都是由一种最基本的类型派生出的子类型。C. Strachey指出,多态是一种参数化的多态,而重载则是一种特殊的多态。用以判断不同的重载函数的机制就是函数标示(function signature)。
重载在下面的例子中显得很有用:
max( int, int )
max( real, real )
这将确保相对于类型int和real的最佳的max函数实体被调用。但是,面向对象的程序设计为该函数提供了一个变量,对象本身被被当作一个隐藏的参数传递给了函数(在C++中,我们把它称为this)。由于这样,在面向对象的概念中又隐式地包含了一种对等的但却更有更多限制的形式。对于上述讨论的一个简单例子如下:
int i, j;
real r, s;
i.max(j);
r.max(s);
但如果我们这样写:i.max(r),或是r.max(j),编译器将会告诉我们在这其中存在着类型不匹配的错误。当然,通过重载运算符的操作,这样的行为是可以被更好地表达如下:
i max j 或者
r max s
但是,min和max都是特殊的函数,它们可以接受两个或者更多的同一类型的参数,并且还可以作用在任意长度的数组上。因此,在Eiffel中,对于这种情况最常见的代码形式看起来就像这样:
il:COMPARABLE_LIST[INTEGER]
rl:COMPARABLE_LIST[REAL]
i := il.max
r := rl.max
上面的例子显示,面向对象的编程典范(paradigm),特别是和泛型化(genericity)结合在一起时,也可以达到函数重载的效果而不需要C++中的函数重载那样的声明形式。然而是C++使得这种概念更加一般化。C++这样作的好处在于,我们可以通过不止一个的参数来达到重载的目的,而不是仅使用一个隐藏的当前对象作为参数这样的形式。
另外一个我们需要考虑的因素是,决定(resolved)哪个重载函数被调用是在编译阶段完成的事情,但对于重写来说则推后到了运行期间。这样看起来好像重载能够使我们获得更多性能上的好处。然而,在全局分析的过程中编译器可以检测函数min和max是否处在继承的最末端,然后就可以直接的调用它们(如果是的话)。这也就是说,编译器检查到了对象i和r,然后分析对应于它们的max函数,发现在这种情况下没有任何多态性被包含在内,于是就为上面的语句产生了直接调用max的目标代码。与此相反的是,如果对象n被定义为一个NUMBER,NUMBER又提供一个抽象的max函数声明(我们所用的REAL.max和INTERGER.max都是从它继承来的),那么编译器将会为此产生动态绑定的代码。这是因为n既可能是INTEGER,也有可能是REAL。
现在你是不是觉得C++的这种方法(即通过提供不同的参数来实现函数的重载)很有用?不过你还必须明白,面向对象的程序设计对此有着种种的限制,存在着许多的规则。C++是通过指定参数必须与基类相符合的方式实现它的。传入函数中的参数只能是基类,或是基类的派生类。例如:
A.f( B someB ) {...}
class B ...;
class D : public B ...;
A a;
D d;
a.f( d );
其中d必须与类'B'相符,编译器会检测这些。
通过不同的函数签名(signature)来实现函数重载的另一种可行的方法是,给不同的函数以不同的名字,以此来使得它们的签名不同。我们应该使用名字来作为区分不同实体(entities)的基础。编译器可以交叉检测我们提供的实参是否符合于指定的函数需要的形参。这同时也导致了软件更好的自记录(self-document)。从相似的名字选择出一个给指定的实体通常都不会很容易,但它的好处确实值得我们这样去做。
[Wiener95]中提供了一个例子用以展示重载虚拟函数可能出现的问题:
class Parent
{
public:
virutal int doIt( int v )
{
return v * v;
}
};
class Child: public Parent
{
public:
int doIt( int v, int av = 20 )
{
return v * av;
}
};
int main()
{
int i;
Parent *p = new Child();
i = p->doIt(3);
return 0;
}
当程序执行完后i会等于多少呢?有人可能会认为是60,然而结果却是9。这是因为在Child中doIt的签名与在Parent中的不一致,它并没有重写Parent中的doIt,而仅仅是重载了它,在这种情况下,缺省值没有任何作用。
Java也提供了方法重载,不同的方法可以拥有同样的名字及不同的签名。
在Eiffel中没有引入新的技术,而是使用范型化、继承及重定义等。Eiffel提供了协变式的签名方式,这意味着在子类的函数中不需要完全符合父类中的签名,但是通过Eiffel的强类型检测技术可以使得它们彼此相匹配。

陷阱重重的C++赋值重载函数operator=

陷阱重重的C++赋值重载函数operator=,菜鸟进阶需掌握之!
  • linqingwu75
  • linqingwu75
  • 2014-11-12 09:34:38
  • 1528

一个对c++的批评

继承机制 一方面是为了扩展,但是另外一方面也是限制, 父类的设计必须完美,考虑到所有子类的可能情况。 这是一个对c++的批判。 认真考虑一下这个问题,这种情况只有在类关系交错的时候才 会发生,情...
  • zergbird
  • zergbird
  • 2004-06-30 21:37:00
  • 738

C++批评系列

 C++批评系列(C++?? A Critique of C++ and Programming and Language Trends of the 1990s)要想彻底的掌握一种语言,不但需要知道...
  • jemmy
  • jemmy
  • 2005-10-13 22:29:00
  • 1065

【C++拾遗】 C++函数重载、重写、重定义的区别

函数重载(overload) 函数重载是指在一个类中声明多个名称相同但参数列表不同的函数,这些的参数可能个数或顺序,类型不同,但是不能靠返回类型来判断。特征是: (1)相同的范围(在同一个作用域中);...
  • Xiejingfa
  • Xiejingfa
  • 2015-09-16 17:00:55
  • 5391

C++批评系列——多继承

多继承Ian Joynercber 译Eiffel和C++都提供了多继承的机制。但Java却没有,因为它认为多继承会导致许多问题的出现。不过Java提供了接口(interface)作为一种替换机制,它...
  • luckysky
  • luckysky
  • 2005-03-04 15:21:00
  • 1003

函数重载的意义详细说明

c++的函数的重载可以说是c++比较常用并且重要的特性了,深入底层的了解函数的重载对这个特性的灵活运用起到很关键的作用,很多也是自己通过自己的角度理解这个特性,还是从内存的存储机制的角度上看函数的重载...
  • panker2008
  • panker2008
  • 2015-06-05 13:30:25
  • 3091

C++函数重载与重载原理:命名倾轧

一、重载概念与原则:1、重载概念:在C语言中,一个函数不能与另一个函数重名,而在C++中,只要一个函数的参数列表与另一个函数的参数列表不完全相同,函数名就可以相同。C++这一特点就是所谓函数的重载现象...
  • Apollon_krj
  • Apollon_krj
  • 2017-03-07 13:59:41
  • 1560

C++ 函数重载 详解

在实际开发中,有时候我们需要实现几个功能类似的函数,只是有些细节不同。例如希望交换两个变量的值,这两个变量有多种类型,可以是 int、float、char、bool 等,我们需要通过参数把变量的地址传...
  • zhanghow
  • zhanghow
  • 2016-12-12 21:20:08
  • 20978

C++函数重载(3) - 函数重载中的const关键字

const可用于重载成员函数 参考下面程序的输出: #include using namespace std; class Test { protected: int x; p...
  • shltsh
  • shltsh
  • 2015-05-24 00:50:31
  • 2012

为什么C++有函数重载

为什么C++支持函数重载? 1、首先,我们需要了解的是,在c中,要求在同一个作用域中,函数名唯一。就是不允许函数同名。 而在C++中,要求同一个作用域中函数签名唯一。函数签名是函数名+参数列表。就是说...
  • mydad353193052
  • mydad353193052
  • 2015-06-15 10:02:56
  • 1089
收藏助手
不良信息举报
您举报文章:C++批评系列:函数重载
举报原因:
原因补充:

(最多只允许输入30个字)