文章目录
引入:
为什么要函数重载?
这个问题其实就是为了解决函数名字的冲突问题,因为假如有一个方法是动作洗, 那么如果是洗车洗衣服洗袜子都得是具体的名字, 这样多不好呀!
必然性:
名字写得烦也就算了,不是必然性的, 但是构造函数的实现,如果要需要实例化多重或者是多类的实例怎么办,一样得必须重载
为什么不能用返回值重载?
这个问题的答案就是一般编译器内部都会将函数重新取一个名字,常用方法都是函数名+ 参数类型1 + 参数类型2 + 参数类型3 + 。。。看到了吧,新的名字根本就没有返回值, 所以重载返回值是不行的,c++也是禁止了的更糟糕的一个问题是连写程度的都不知道会调用哪个函数
为什么函数需要默认参数?
这个问题的答案其实可以归结为上面那个问题,当函数被重载了多个之后,那么必然参数也是各种各样的(重载只能动参数)可能有一大堆的函数就一点儿不同,却得每次调用都需要些一堆的参数, 这个我是不想这样做的,所以就用这个方法解决问题
深入:
类型安全连接
编译器生成可执行文件的时候是编译 - 》连接。而且编译的时候为了省时间是单个文件编译的,就是一个文件就是一个编译单元, 然后再用连接器将所偶的编译单元连接起来重新生成可执行文件,就是因为这样的机制,也导致了一点儿点儿的大问题假如现在有两个文件,其中1.cpp中有如下定义
//1.cpp
void oyl(int v){}而2.cpp有如下声明:void oyl(char v);
由于是单个文件的编译机制,那么1.cpp, 2.cpp都会编译成功,如果在c中,链接也会成功,所以在c的编译器中会产生一个找到胡子白的难发现的bug, 而在c++的编译器中,由于在 上面(为什么不能用返回值重载?)中的这种机制将发现这个错误,从而类型安全链接。所以用c++编译器找找c项目中的bug估计很爽
重载的例子
略了好了
默认参数例子
同上好了
选择重载还是默认参数呢?
表示这个就别略了
自写一个string类:
1. mem.h, 这个是自己写的内存管理的头文件:
/* encoding by ygqwan in 2013/ 8 / 10 */ //: mem.h #define MEM_H typedef unsigned char byte; class Mem { byte * mem; //这块内存的首地址 int size; //这块内存的大小 void ensureMinSize(int minSize); //确保内存大小值最次也比minSize大 public: Mem(); Mem(int sz); //构造一个大sz 的内存块 ~Mem(); int msize(); byte *pointer(); //返回内存块儿的首地址 byte *pointer(int minSize); //一样的作用,只是这里多了一步增加内存大小的作用 };
2. mem.cpp 对mem.h里面的声明进行定义:
/* encoding by ygqwan in 2013/ 8 / 10 */ //:mem.cpp 主要做内存的分配和相关处理,但是这里的内存是只会不不会减 #include "mem.h" #include <cstring> using namespace std; Mem::Mem(){ mem = 0; size = 0; } Mem::Mem(int sz){ mem = 0; size = 0; ensureMinSize(sz); } Mem::~Mem(){ delete []mem; } int Mem::msize(){ return size; } void Mem::ensureMinSize(int minSize){ if(size < minSize){ byte *newmem = new byte[minSize]; memset(newmem + size, 0, minSize - size); memcpy(newmem, mem, size); delete []mem; mem = newmem; size = minSize; } } byte* Mem::pointer(){ return mem; } byte* Mem::pointer(int minSize){ ensureMinSize(minSize); return mem; }
3. MyString.cpp , 这个就是自己的string类了:
/* encoding by ygqwan in 2013/ 8 / 10 */ #include "mem.h" #include <cstring> #include <iostream> using namespace std; class MyString { Mem *buf; public: MyString(); MyString(char * str); ~MyString(); void concat(char * str); //在原有串的后面增加str串 void print(ostream & os); }; MyString::MyString(){ buf = 0;} MyString::MyString(char *str){ buf = new Mem(strlen(str) + 1); strcpy((char *)buf->pointer(), str); } void MyString::concat(char * str){ if(!buf) buf = new Mem(); strcat((char *)buf->pointer(buf->msize() + strlen(str)), str); } void MyString::print(ostream & os){ if(!buf) return; os << buf->pointer() << endl; } MyString::~MyString(){ delete buf; } int main() { MyString * s = new MyString("oyl"); s->concat("wan"); s->print(cout); MyString * s2 = new MyString(); s2->concat("...wan"); s2->print(cout); return 0; } MyString(char *str) { if(*str == 0) buf = 0; return; }
从上面的代码可以看到如下特性:
MyString()和MyString(char *str)同时都有, 无参数的主要是为了同时创建很多空的string, 这里的时间花销就是给buf付了一个初始值0而已, 如果我们使用默认参数的形式就不一样了, 花销就大了不能把默认参数作为一种标志去决定执行函数的哪一块, 这是铁一般的定则, 避免这样的做法就是把函数分开或者重载多个,就上面的MySstring就重载了,而不是使用默认参数去决定执行函数的哪一块儿大放送
默认参数的一个重要应用就是在开始定义函数的时候用了一组参数, 而是用了今年后,客户没事儿找事儿做说要增加新的功能, 那么很有可能需要增加这个函数的参数的个数, 那么这个时候就可以将新增加的参数都作为默认参数, 这样就完全不用去改变以前调用这个函数的代码了,省事不少呀
总结:
有点儿结巴了