钱能C++程序设计教程第一版总结

时间:2022-06-07 03:13:49

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一下那天面我的那个人,实在是有些太自我了。