湘潭九华 地铁 科大站:关于C++指针引用自相矛盾的一个现象!!!!

来源:百度文库 编辑:神马品牌网 时间:2024/04/30 02:40:06
先看这两个例子.
#include<iostream>
using namespace std;
void swap(int &,int &);/*不懂1:这个必须放在函数外面.否则错误*/
int main()
{int i=3,j=5;/*把不懂1放在这儿,错误错误!!!!!运行结果为i=3 j=5完全错误*/
swap(i,j);
cout<<"i="<<i<<" "<<"j="<<j<<endl;
return 0;}
void swap(int &a,int &b)
{int temp;
temp=a;a=b;b=temp;}
运行结果:i=5 j=3
例2
#include<iostream>
using namespace std;
int main()
{void sort(int &,int &,int &);/*不懂2:这个和不懂1不同,可放在里面也可放在函数外面*/
int a,b,c;int a1,b1,c1;
cout<<"Please enter 3 integers:";
cin>>a>>b>>c;
a1=a;b1=b;c1=c;sort(a1,b1,c1);
cout<<"sorted order is "<<a1<<" "<<b1<<" "<<c1<<endl;
return 0;}
void sort(int &i,int &j,int &k)
{void change(int &,int &);/*不懂3:这又是一个调用函数,依然可以放在里面或外面都正确*/
if(i>j) change(i,j);
if(i>k) change(i,k);
if(j>k) change(j,k);}
void change(int &x,int &y)
{int temp;temp=x;x=y;y=temp;}
运行结果:自己随便输3个数,比较这个数大小,调试正确
发现这2个例子的不同处没有????!!!!很难理解啊!!这样好像自相矛盾.
为什么第一个例子必须要放在外面?为什么其他2个例子里外都可放!
例1.只能定全局变量,首先那个调用函数是放在主函数后,而且这里就2个函数..1个主与调用函数.只要是定义在调用函数的都符合先定义后使用规则,首先

不想打了...唉!!!这儿我举的例子反差太大了!!!!两个都是引用.平等,却完全不一样

谢谢..高手...是的你说的完全正确..可是这其中还隐藏着一个问题!!!首先看我举的例子..既然例2都可以运行.所以我用例1仿照例2改了一下程序..
#include<iostream>
using namespace std;
int main()
{void swap(int *,int *);
int i,j;int a1,b1;
cin>>i>>j;
a1=i;b1=j;
swap(&a1,&b1);
cout<<a1<<" "<<b1<<endl;
return 0;}
void swap(int *p1,int *p2)
{int temp;
temp=*p1;*p1=*p2;*p2=temp;}
程序在VC6.0程序运行情况下正确.实现了两个值互换.只不过是要自己输入.但这不重要,重要的是和你介绍的第2种有点冲突..首先1.我没修改swap(虽然它是C++库函数),2,那个void依旧定义在main函数内.
真不好意思,一个问题引出一个问题..

我想了想,可能这和你说的第2种有点相似,就是VC6.0编译器问题

总结了一下,归结2点.1编译器问题!2.库函数
谢谢你!!!!如果有100分,一定全送给你了..

楼主比较善于思考,对于这个怪现象,自己也去调试了一下,发现一些问题,在此先看以下代码。

样例1:

#include <iostream>
using namespace std;

template<class T> void A( T& a )
{
cout<<"Template Function"<<endl;
}

void A( int & a );//在此声明函数A,将会“重载”上面的模板函数!

int main()
{
int i = 0;
A( i );
return 0;
}

void A ( int & a )
{
cout<<"A Function"<<endl;
}
对于此例,VC6和VC.NET2003及以上版本均会做出正确的选择,此时会输出 "A Function".表明调用的是常规函数版本。MSDN上对此也有如下解释:“模板函数也可以被一般的普通函数重载,实际函数调用时,首先会实例化模板,看是否能正确产生无歧义的函数实例,如果能产生,将会把这个函数实例作为候选函数之一。对于那个常规函数,如果完全吻合调用时参数传递的语义,或者编译器可以通过默认的类型转换使之满足语义,也将它作为候选函数之一。对于这样一个候选函数集合,编译器最终会选择一个‘完美’吻合的版本。(即不用任何默认的类型转换,实际参数本身就符合该函数的参数调用语义)如果普通的函数和模板函数均‘完美’吻合。则选择普通函数!”(原文大意)

再看另一个例:
样例2:

#include <iostream>
using namespace std;

template<class T> void A( T& a )
{
cout<<"Template Function"<<endl;
}

int main()
{
void A( int & a );//在此声明函数A,将会“覆盖”上面的模板函数!
int i = 0;
A( i );
return 0;
}

void A ( int & a )
{
cout<<"A Function"<<endl;
}

对于样例2,VC6和VC.NET2003及以上版本行为有所不同。
1。在VC6中,发现没有任何输出,即没有调用任何版本的函数A。通过观察生成的汇编代码,证实了这一点。没有生成函数调用的"call ..."指令!
2。在VC.NET2003及以上版本中,会输出"A Function",即调用了函数A的普通版本。为什么呢?因为在main()函数内声明函数A,其作用域为从声明那一行开始,到main()函数结束,并且这个声明将会“覆盖”任何处于外层(main()函数之外)的同名函数。所以很正常,因为这里的声明覆盖了外层的模板函数A,编译器自然会采用A函数的普通版本了。
为什么VC6会有那么不正常的行为?别忘了,VC6对于C++标准并非完全符合,即使VC.NET也只是90%以上符合C++标准,而VC6的奇怪行为,也可以看作编译器的一个小BUG吧^_^

现在回过来看楼主的例子。对于第一个例子,swap其实是一个库函数,而且是一个模板函数!可以查到源代码为:
template<class _Ty> inline
void swap(_Ty& _X, _Ty& _Y)
{
_Ty _Tmp = _X;
_X = _Y, _Y = _Tmp;
}
楼主自定义的函数非常偶然的和库函数同名。这下就豁然开朗了吧~SWAP不就是上面举例中的函数A么^_^
而后面两个例子,不会出现这种意外重载或者覆盖库函数的情况,所以不管在哪声明,行为都会很正常~~~~~~~

从你的问题中,就知道你对函数了解不多
还是先学好函数那一章