-
1.
什么是多态
多
态是
C++
中的一个重要的基础,可以这样说,不掌握多态就是
C++
的门个
汉。我就给它定一个这样
的名字
--
“调用’同名函数’却会因上下文不同会有
不同的实现的一种机制”
。这个名字长是长了点儿,可是比“多态”清
楚多了。
看这个长的定义,
我们可以从中找出多态的三个重要的
部分。
一是
“相同函数名”
,
二是“依据上下文”
,三是“实现却不同”
。我
们且把它们叫做多态三要素吧。
2.
多态带来的好处
多态带来两个明显的
好处:
一是不用记大量的函数名了,
二是它会依据调用
时的上下文来确定实现。确定实现的过程由
C++
本身完成,另外还有一个不明显
但却很重要的好处是:带来了面向对象的编程。
3.
C++
中实现多态的方式
C++
p>
中共有三种实现多态的方式。由“容易说明白”到“不容易说明白”排
序分别为
:
第一种是函数重载;第二种是模板函数;第三种是虚函数。
4.
细说用函数重载实现的多态
<
/p>
函数重载是这样一种机制:允许有不同参数的函数有相同的名字。
具体一点讲就是:假如有如下三个函数:
void test(int arg){}
//
函数
1
void
test(char arg){} //
函数
2
void test(int arg1,int arg2){}
//
函数
3
如果在
< br>C
中编译,将会得到一个名字冲突的错误而不能编译通过。在
C++
中
这样做是合法的。
可是当
我们调用
test
的时候到底是会调用上面三个函数中的哪
p>
一个呢?这要依据你在调用时给的出的参数来决定。如下:
test(5); //
调用函数
1
test('c');//
调用函数
2
test(4,5);
//
调用函数
3
C++
是如何做到这一点的呢?原来聪明的
C++
编译器在
编译的时候悄悄的在
我们的函数名上根据函数的参数的不同做了一些不同的记号。具体说
如下:
void test(int arg) //
被标记为‘
test
有一个
< br>int
型参数’
void
test(char arg) //
被标记为‘
test
p>
有一个
char
型的参数’
void test(int arg1,int arg2) //
被标记为
‘
test
第一个参数是
int
型,
第二个参数<
/p>
为
int
型’
这样一来当我们进行对
test
的调用
时,
C++
就可以根据调用时的参数来确定
到底该用哪一个
test
函数了。噢,聪明的
C++
编译器。其实
C++
做标记做的比我
上面所做的更聪明。我上面哪样的标记太长了。
C++
编译器用的标记要比我的短
小的多。看看这个真正的
p>
C++
的对这三个函数的标记:
?test@@YAXD@Z
?test@@YAXH@Z
?test@@YAXHH@Z
是不是短多了。
但却不好看明白了。
好在这是给计算机看的,
人看不
大明白
是可以理解的。
还记得
cout
吧。我们用
<<
可以让它把任意类型的数据输出。比如可以象下
面那样:
cout << 1; //
输出
in
t
型
cout << 8.9; /
/
输出
double
型
cout << 'a'; //
输出
char
型
cout
<<
输出
char
数组型
cout << endl;
//
输出一个函数
cout
之所以能够用一个函数名
<<
(
<<
是一个函数名)
就能做到这些全是函数
重载的功能。要是没有函数重载,我们也许会这样使用
cout
,如下:
cout int<< 1; //<
/p>
输出
int
型
cout double<< 8.9; //
输出
double
型
cout char<< 'a'; //
输出
char
型
cout
charArray<<
输出
char
数组型
cout
function(
?
)<< endl;
//
输出函数
为每一种要输出的类型起一个函数名,这岂不是很麻烦呀。
<
/p>
不过函数重载有一个美中不足之处就是不能为返回值不同的函数进行重载。
那是因为人们常常不为函数调用指出返回值。
并不是技术上不能通过返回值来进
行重载。
5.
细说用模板函数实现的多态
所谓模板
函数(也有人叫函数模板)是这样一个概念:函数的内容有了,但
函数的参数类型却是待
定的(注意:参数个数不是待定的)
。比如说一个
(
准确的
说是一类或一群
)
函数带有两个参数,它的功能是返回其中的大值。这样的函数
用模板函数来实现是适合不
过的了。如下。
template < typename
T>
T getMax(T arg1, T arg2)
{
return arg1 > arg2 ?
arg1:arg2; //
代码段
1
}
这就是基于模板的多态吗?不是。因为现在我们不论是调用
getMax(1,
2)
还
是调用
getMax(3.0, 5.0)
都是
走的上面的函数定义。
它没有根据调用时的上下文不
同而执行不
同的实现。所以这充其量也就是用了一个模板函数,和多态不沾边。
怎样才能和多态沾上
边呢?用模板特化呀!象这样:
template<>
char* getMax(char* arg1, char* arg2)
{
return (strcmp(arg1, arg2)
> 0)?arg1:arg2;//
代码段
2
}
这样一来当我们调用
getMax
(
“
abc
”
,
“
efg
”
)
的时候,就会执行代码段
2
,
p>
而不是代码段
1
。这样就是多态了。
更有意思的是如果我们再写这样一个函数:
char getMax(char arg1, char arg2)
{
return
arg1>arg2?arg1:arg2; //
代码段
3
}
当我们调用
getMax(
‘
a
’
,
‘
b
’
)
的时候,执行的会是代码段
3
,而不是代
码段
1
或代码段
2
。
C++
允许对模板函数进行函数重载,就象
这个模板函数是一
个普通的函数一样。
于是我们马上能想到写下
面这样一个函数来做三个数中取大
值的处理:
int getMax( int arg1, int arg2, int
arg3)
{
return getMax(arg1,
max(arg2, arg3) ); //
代码段
4
}
同样我们还可以这样写:
template
T
getMax(T arg1, T arg2, T arg3)
{
return getMax(arg1, getMax(arg2, arg3)
); //
代码段
5
}
现在看到结合了模板的多态的威力了吧。比只用函数重载厉害多了。
6.
小结
上面的两种多态在
C++
中有一个总称:静态多态。之所以叫它
们静态多态是
因为它们的多态是在编译期间就确定了。
也就是说
前面所说的函数
1
,
2
,
3
代码
段
< br>1
,
2
,
3
,
4
,
5
这些,在编译完成后,应该在什么样的上下文的调用中执行<
/p>
哪一些就确定了。比如:如果调用
getMax(0.1,
0.2, 0.3)
就会执行代码段
5
。如果
调用
test(5)
就执行函数
1
。这些是在编译期间就能确定下来的。
静态多态还有一个特点,就是:
“总和参数较劲儿”
。
下面所要讲的一种多态就是必需是在程序
的执行过程中才能确定要真正执
行的函数。所以这种多态在
C+
+
中也被叫做动态多态。
7.
细说用虚函数实现的多态
7.1.
虚函数是怎么回事
首先来说一说虚函数,
所谓虚函数是这样一个概念:
基类中有这么一些函数,
这些函数允许在派生类中其实现可以和基类的不一样。在<
/p>
C++
中用关键字
virtual
来表示一个函数是虚函数。
C++
中还有一个术语“覆盖”与虚函数关系密切。所谓覆盖就是说,派生类
中
的一个函数的声明,与基类中某一个函数的声明一模一样
,
包括
返回值,函数
名,参数个数,参数类型,参数次序都不能有差异。
(注
1
)说覆盖和虚函数关
-
-
-
-
-
-
-
-
-
上一篇:英语求职信万能模板
下一篇:感悟曼德拉名言警句中英文大全