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