1. 函数声明与函数本身的关系
如果函数声明与函数本身名称相同,但是参数不同, 则会出现编译通过,但链接失败.
例:声明时: void funA(int , float);
函数本身:void funA(int a, int b)
{
//…
}
2. 函数声明时,参数的默认值可以是全局变量, 全局常量,甚至是一个函数.
例: int func(int a)
{
return a*2;
}
int a =43;
int g(int x=func(a)) //此处默认参数值为一个函数. 调用这个函数可以直接用g();
{
cout<<"In g() function, x=:"<<x<<endl;
return 0;
}
3. 当函数又有声明又有定义时, 定义中不允许默认参数. 当没有声明时,定义中才可以出现默认参数.
4. 函数的默认定义或声明总是extern的. 相当于省略了extern void fun(); 带extern的变量说明是变量声明, 不是变量定义.
5. Static 变量或者函数,是指这个全局变量或静态函数对之外的源文件是不可见的.
6. 指向指针的指针
指针数组是数组, 是数组则其名字便为指针常量, int *const Array;(故不能进行数组名的自加或自减.). 指针数组名是指向指针的指针(即二级指针)
例1: 定义和赋值
char *pc[]={“abc”, “Jack”, “Hone};
char **ppc;
ppc = pc;
例2:使用
Void main()
{
Char *pn[] ={“Fred”, “Barney”, “Betty”};
Print(pn, 3);
}
Void Print(char *arr[], int len)
{
For(int i=0; i<len; i++)
{
Cout<<arr[i]<<endl;
}
}
7. 返回堆中变量的引用
对引用的初始化, 可以是变量, 可以是常量, 也可以是一定类型的堆空间变量.但是,由于引用不是指针,所以直接从堆中获得的变量空间来初始化引用是不行的. 考虑操作符new, 如果new不能在堆空间里成功地获得内存分配, 它返回NULL. 因为引用不能是NULL, 在程序确认它不是NULL这前, 程序是不能用这一内存初始化引用的.
例1: int &a= new int(2); // 编译会报错Can’t convert from int *' to 'int &
例2: 用法
int CircleArea()
{
double *pd = new double; //所以如果要用引用来指向堆内存, 应先用指针赋值, 并进行空值判断,然后再赋给引用.
if(!pd)
{
cout<<"Error memory allocation!"
return 1;
}
double &rd = *pd;
//用了之后进行释放
delete &rd; //或者delete pd; 等效释放
return 0;
}
8. 浅拷贝和深拷贝
浅拷贝, 创建一个复制出来的对象时,如果没有复制其资源, 使得复制出来的对象与原象仍指向同一资源, 这就称为浅拷贝.
例: class Person
{
public:
Person(char *pn)
{
cout<<"Constructing:"<<pn<<endl;
pName = new char[strlen(pn)+1]; //这里有堆内存资源的申请
if(pName !=0)
{
strcpy(pName, pn);
}
}
~Person()
{
cout<<"Destructing:"<<pName<<endl;
pName[0]='/0';
delete pName;
}
protected:
char *pName;
};
int main(int argc, char* argv[])
{
Person p1("Jacky");
Person p2 = p1; //这里进行了拷贝函数的调用, 尽管调用的是默认拷贝函数.
return 0;
}
输出结果:
Constructing:Jacky
Destructing:Jacky
Destructing:不识别的字符,
并弹出了Assert 的错误, Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
这是因为在调用拷贝时,只会进行默认的拷贝调用, 即拷贝protected下的char* pName;, 而这仅仅是一个指针, 而不会在拷贝的时候进行构造函数的调用, 所以在进行析构时, 会被析构两次.
解决办法是:
当一个对象创建时, 分配了资源, 那么就需要为它自己定义一个拷贝构造函数, 使之不但拷贝成员, 也拷贝资源. (个人认为, 这个拷贝构造函数,只需要把构造函数的大部分粘贴过来即可.)
所以为上例中加入一个拷贝构造函数, 加入后, 则变成了深拷贝, 同时也复制了资源, 即称深拷贝.
Person:: Person(Person &p)
{
cout<<"In Copy, copying:"<<p.pName<<endl;
pName = new char[strlen(p.pName)+1];
if(pName !=0)
{
strcpy(pName, p.pName);
}
}
这样即可.
注意: 如果类需要析构函数来析构资源, 则它也需要一个拷贝构造函数. 例如: 堆内存, 打开文件, 占有硬设备(例如打印机)服务等都会需要深拷贝.
后记:仔细看这本书的初衷本来是为了进MS做一个SDE的Vender的,结果因为诸多原因,还是没有进去,有些小小的惆怅,不过顺便再次学习了本该以前毕业时就该掌握的东东,也算是给自己有个交待吧。不过实话来说,也许是是与MS无缘吧。
然后顺便偷偷地BS一下那天面我的那个人,实在是有些太自我了。