C++与C#对比学习:函数(二)返回值,默认实参.this指针

时间:2022-08-31 09:11:11

函数返回值

我们定义函数时会指定一个返回值类型,那在函数体中必须返回一个匹配的类型,或者隐式转换后能匹配的类型.不过有时存在这样的情况,如果函数体中存在一些分支语句,有些情况是可以返回一个值,但有时不会返回值.还是举个例子吧.

有如下C++函数

int FunArwen(int a , int b)

{

if(a < b)

     return 888;

}

很显然,上面的函数有时会返回一个值,但有时又不会.

int result = FunArwen(4,5);      //这时结果是888;

 

int res     = FunArwen(5,4);      

//这时函数不会有返回值,不过我在VS中运行得到res为5,貌似返回了第一个参数的值.不知道为啥是这个值,没太搞懂.

//不过反正这肯定是个错误的结果.

 

在C++中上面的函数编译时会有一个警告信息"not all control paths return a value", 而在C#中上面的函数不能通过编译的,会报错,"not all code paths return a value".

你必须写成 if (a < b) return 888 ;

                   else return 44;

或者if(a < b) return 888;      return 444;

这样才能编译通过

 

C#针对C++中的很多地方都做了一些改进,多做了一些检查.使你写出来的代码更不容易出错.其实一个编程语言的发展很多时候关注的一是,简化一些复杂的语法,使你能用更少的代码实现更多的功能.另一个是多做一些检查,要编译期间就给你检查出一些错误来.当然准确的讲有些错误也不是真正的错误,只要有潜在的犯错可能就当作错误处理了.

我们平时不是常讲软件测试嘛,其实编译器做的工作也算是测试的一种,给你把代码中的语法错误找出来.如果任何错误都能在编译期间都找出来自然是最完美的,不过编译器可没这么聪明.很多运行时错误它是没法检测出来的.

 

C++返回局部函数体中局部变量指针或引用的问题

另外值得注意的是在C++中如果返回结果是函数体中的局部指针或引用类型.则会出错,因为函数体中的局部变量一超过作用域就会被释放了.所以指针就变成野指针了.不知道指到哪去了.举个例子

int*  GetResult( )

{

  int num = 110;

  int* ip = &num;

 return ip;

}

int* p = GetResult();    //这样做是错误的,不过有时错误的操作也会得到正确的结果.

//你运行时可能出现运行时错误,可能运行正确得到个错误的结果,有时还可能得到正确的结果.反正我在VS中试的时候是得到个正确的结果的.

因为num超出作用域之后就告诉系统那块内存它不要了,系统可以把那内存分配给别人用了.不过如果那内存暂时还没被分给谁,那里面的值还仍然在,所以你通过指针去访问那个值时可能还能得到个正确的值

 

默认实参

 

假如某个函数的参数有很多个,我们调用时要传那么多个参数进去非常麻烦,而且有些参数不那么重要,我们整个啥默认值就行.你首先想到的可能是来个函数重载,整很多个函数出来,但参数个数都不一样.显然这确实是一个办法.但实现的不够优美.在C++中有个默认实参的做法能更好的解决这问题.举例

void Register(string userName = "打酱油的"

,string pwd = "123"

, int age = 18

)

{

//do something

}

这样我们调用函数时可以像下面那样

Register();

Register("arwen");

Register("arwen","911");

Register("weiwen","110",24);

上面那样调用都正确,不过你这样调用就不行

Register("wei", 24);     //会出错.因为系统是从左到右去匹配.你传两个参数它只会去匹配userName和pwd

 

C#中没有默认实参

不过有点遗憾的是C# 2.0, 3.0中都没有提供这个功能.据说c# 4.0有提借这功能.不过我还从没用过4.0.微软的东西更新太快,要老想去跟着赶时髦会很累的啊.还是老实的把基础打好再说

 

 

This 指针

举个例子,有C++类Arwen

class  Arwen

{

private:

     int age;

     int height;

public:

      void  SetAge(int age)

       {

            this ->age = height;

         }

       void SetHeight(int hgt)

         {

             height = hgt;

}  

}

 

Arwen wen;

int hgt = 111;

wen.SetHeight(hgt);   //我们知道每个类的函数跟static变量一样是不属于某个实例的,所以的实例对象都使用共一个函数.函数是保存在代码区.那我们这样调用函数时,怎么能找到函数呢?实际上你像上面这样调用一个函数时编译器会默认把它 转换成

Arwen::SetHeight(&wen  , hgt);

然后给height赋值就是这样 wen.height =  hgt;     //默认情况都是给自成员变量前加个实例对象做前缀.&wen也就是this指针了.

但如果成员变量和传的参数同名了就必须显式加this指针.

像SetAge中 this->age = age;

 

const函数

我们可以在函数后面加个const,例如void SetAge(int age) const { this->age = age;}

Arwen wen;

int age = 222;

wen.SetAge(age); //此时出错了.

因为编译器把上面的调用中的this指针转化成指向const类型的指针了,所以不用this->age = age;这样去修饰指针指向的值了.

 

 

C#中的this的用法和原理跟C++差不多.虽然C#中没有指针的概念,但我猜实际上后台很多实现最终都是通过指针实现的.估计C#的编译器也是用C++和C开发的吧.连微软的操作操作都是C++和C开发的.