您的位置:首页 > 编程语言 > C语言/C++

c++学习杂记(2)

2007-04-07 17:02 337 查看
类和结构:

class和struct的比较:struct是简化数据逻辑结构的设计,本质上属于自定义的数据结构;class是将数据与方法封装,让行为和数据一致,本质上是一种程序设计方法,折射了一种编程思想。struct不能包括函数,而class可以,在struct里成员默认属性(存储控制)是private而struct默认属性是public。

c的struct和c++的struct的区别:在c中说明结构对象的方法是:struct xxxx a;c++为:xxxx a,struct可以不用。

c中结构不能有成员函数,c++的struct可以有。

c++种class和struct的区别:存储控制不同。

个人认为c++种的结构应该属于class的范畴。

class:

在类里定义的成员函数规模小,而且奴允许用switch语句,默认为inline函数,其调用在源程序中原地扩展,不调用堆栈,故可以放在头文件里,而一般函数的定义不能放在头文件里,因为这意味着它将被编译多次。

最好将类定义和成员函数定义分开,将类定义视为类的外部接口,而成员函数视为其内部实现。将类成员定义为私有成员函数定义为公有是很好的风格。

类名是类成员函数的一部分,故不同类的内部同名的成员函数,不能视为重载。

当一个类有多个实例时,每个成员函数都调用同一段代码,那该成员函数这么识别数据是属于不同的实例呢?其实当成员函数接受实参时,还接受了具体实例的地址,而且这个地址被隐藏的形参this获得即this=&xx,故访问的数据成员前都隐含加了this->,这就是类成员函数操作本类数据成员不需要像其他函数加类前缀的原因。

一个类实例所占内存大小由数据成员所占空间的总和决定,当然与成员函数无关。

类的作用域:

类的作用域是指类定义和成员函数对应的范围,类成员函数对类数据成员有无限制的访问权限。

在成员函数定义与类成员同名的局部作用域变量后就把类成员隐蔽了。类型名可以与变量名或函数名相同,如果非类型名隐藏了类型名,则类型名加前缀即可:

void func(int Sample)

{

class Sample a;

Sample++;

.......

}

如果类型名隐藏了非类型名,用作用域规则即可:

int S;

void func()

{

class S {....};

S s;

::S=3;

}

注:在函数中定义的类叫局部类,局部类的作用域在定义该类的函数块中,局部类的成员函数必须在局部类的内部定义,若在类外函数内定义造成函数嵌套定义,若在在包括类的函数外定义则成员函数无法与类取得联系。

一个名字不能同时指两种类型非类型名(变量,常量,函数,对象,枚举成员)不能重名。在同一个作用域中,一个名字可以同时声明为类型和非类型,同时登场时加各自的前缀即可区别。

构造函数:

构造函数无返回类型,自动调用,无返回值,但可以有无值return语句,不能为virtual(可以为(包括拷贝构造函数)virtual,只是不经常用,现在纠正),可以重载。当类中含有其他类时,各自的构造函数工作如下(最简单的情况):如A中有B,C

当需要创建A的对象时,调用A的构造函数,该构造函数启动,首先分配对象空间,然后按类成员声明顺序依次调用其构造函数,最后才执行A的构造函数的函数体,最后控制返回主函数。

无参数的构造函数叫默认构造函数,显式调用构造函数会创建一个无名对象。

注:c++语法规定,无构造函数的类无法创建对象。若未提供构造函数,那么编译器会自动提供一个默认构造数,无参。只要为一个类定义了一个构造函数以上,编译器不再提供默认构造函数,若还想要无参构造函数,必须自己定义。当创建无参对象时不能有括号:

class A

{

public:A(){}

};

A a();//错误...............1

A b;//正确...................2

其原因是:c++语法规定,1声明了一个函数A只是它的返回类型;

Class a(10);................创建对象

Class b(int);................创建函数

如下程序:

class A

{

pubilc:

A(int id=0)

{

value = id;

}

protected:

int value;

};

class B

{

public:

B(....,int id = 0)

{

A a(id);

.........

}

protected:

A a;

};

main ()

{

B b(......,32);

}

无法将32传给value;因为在构造函数中的A a只是个局部变量,当构造函数结束后就被析构了,value为0,正确的方法是去掉前面的“A”

如果在上面B中加入类似于A a(12);等东西,在B定义时不会调用A的构造函数。

局部和static对象以声明的顺序构造,而且这些对象在函数开始执行时同一定义,其顺序与出现顺序相同,而不是按运行顺序来决定变量定义顺序。

文件作用域的static在main()之前全部构造完毕,块作用域中的static对象在首次进入定义该对象的函数时被构造。全局对象在main()函数之前全部被构造,其顺序随机,故禁止一个全局对象访问另一个全局对象。类成员在类中以声明的顺序被构造。

析构函数:

析构函数无返回类型,无参,不能随意调用无重载,最好为virtual,当多类包含时,析构函数调用与构造函数相反。

类和结构:

class和struct的比较:struct是简化数据逻辑结构的设计,本质上属于自定义的数据结构;class是将数据与方法封装,让行为和数据一致,本质上是一种程序设计方法,折射了一种编程思想。struct不能包括函数,而class可以,在struct里成员默认属性(存储控制)是private而struct默认属性是public。

c的struct和c++的struct的区别:在c中说明结构对象的方法是:struct xxxx a;c++为:xxxx a,struct可以不用。

c中结构不能有成员函数,c++的struct可以有。

c++种class和struct的区别:存储控制不同。

个人认为c++种的结构应该属于class的范畴。

class:

在类里定义的成员函数规模小,而且奴允许用switch语句,默认为inline函数,其调用在源程序中原地扩展,不调用堆栈,故可以放在头文件里,而一般函数的定义不能放在头文件里,因为这意味着它将被编译多次。

最好将类定义和成员函数定义分开,将类定义视为类的外部接口,而成员函数视为其内部实现。将类成员定义为私有成员函数定义为公有是很好的风格。

类名是类成员函数的一部分,故不同类的内部同名的成员函数,不能视为重载。

当一个类有多个实例时,每个成员函数都调用同一段代码,那该成员函数这么识别数据是属于不同的实例呢?其实当成员函数接受实参时,还接受了具体实例的地址,而且这个地址被隐藏的形参this获得即this=&xx,故访问的数据成员前都隐含加了this->,这就是类成员函数操作本类数据成员不需要像其他函数加类前缀的原因。

一个类实例所占内存大小由数据成员所占空间的总和决定,当然与成员函数无关。

类的作用域:

类的作用域是指类定义和成员函数对应的范围,类成员函数对类数据成员有无限制的访问权限。

在成员函数定义与类成员同名的局部作用域变量后就把类成员隐蔽了。类型名可以与变量名或函数名相同,如果非类型名隐藏了类型名,则类型名加前缀即可:

void func(int Sample)

{

class Sample a;

Sample++;

.......

}

如果类型名隐藏了非类型名,用作用域规则即可:

int S;

void func()

{

class S {....};

S s;

::S=3;

}

注:在函数中定义的类叫局部类,局部类的作用域在定义该类的函数块中,局部类的成员函数必须在局部类的内部定义,若在类外函数内定义造成函数嵌套定义,若在在包括类的函数外定义则成员函数无法与类取得联系。

一个名字不能同时指两种类型非类型名(变量,常量,函数,对象,枚举成员)不能重名。在同一个作用域中,一个名字可以同时声明为类型和非类型,同时登场时加各自的前缀即可区别。

构造函数:

构造函数无返回类型,自动调用,无返回值,但可以有无值return语句,不能为virtual,可以重载。当类中含有其他类时,各自的构造函数工作如下(最简单的情况):如A中有B,C

当需要创建A的对象时,调用A的构造函数,该构造函数启动,首先分配对象空间,然后按类成员声明顺序依次调用其构造函数,最后才执行A的构造函数的函数体,最后控制返回主函数。

无参数的构造函数叫默认构造函数,显式调用构造函数会创建一个无名对象。

注:c++语法规定,无构造函数的类无法创建对象。若未提供构造函数,那么编译器会自动提供一个默认构造数,无参。只要为一个类定义了一个构造函数以上,编译器不再提供默认构造函数,若还想要无参构造函数,必须自己定义。当创建无参对象时不能有括号:

class A

{

public:A(){}

};

A a();//错误...............1

A b;//正确...................2

其原因是:c++语法规定,1声明了一个函数A只是它的返回类型;

Class a(10);................创建对象

Class b(int);................创建函数

但是 Class * ptr=new Class();//如果Class类有默认构造函数的话可以。注意这和上面有本质区别。

如下程序:

class A

{

pubilc:

A(int id=0)

{

value = id;

}

protected:

int value;

};

class B

{

public:

B(....,int id = 0)

{

A a(id);

.........

}

protected:

A a;

};

main ()

{

B b(......,32);

}

无法将32传给value;因为在构造函数中的A a只是个局部变量,当构造函数结束后就被析构了,value为0,正确的方法是去掉前面的“A”

如果在上面B中加入类似于A a(12);等东西,在B定义时不会调用A的构造函数。

局部和static对象以声明的顺序构造,而且这些对象在函数开始执行时同一定义,其顺序与出现顺序相同,而不是按运行顺序来决定变量定义顺序。

文件作用域的static在main()之前全部构造完毕,块作用域中的static对象在首次进入定义该对象的函数时被构造。全局对象在main()函数之前全部被构造,其顺序随机,故禁止一个全局对象访问另一个全局对象。类成员在类中以声明的顺序被构造。

析构函数:

析构函数无返回类型,无参,不能随意调用无重载,最好为virtual,当多类包含时,析构函数调用与构造函数相反。

堆与拷贝构造函数:

堆:

1.一个进程在创建时都分配一个静态存储区域、一个堆、一个栈,代码区

2.静态存储区域用于存储进程的全局变量和静态变量;全局变量和静态变量从静态存储区域分配。程序在编译的时候就已经分配好内存的分布,这块内存在程序的整个运行期间都存在。

3.堆
1)程序在运行的时候用malloc或new从堆上动态申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。
2)堆应该是保留的一段内存空间,在进程初始化的时候,系统会提交一部分物理存储。进程的堆的初始大小默认是1MB。物理存贮的提交和回收应该是由堆管理器来管理的。堆应该是自动增长的。我们说的“自动生长”指的是在预先保留的全部堆空间都不够用的时候,重新来从自由区域留。

3)堆对象的作用域是整个程序生命期。在对上分配数组,只能调用默认构造函数。若没有,出错!

4.每一个函数都可以对栈操作,用于存储参数和局部变量。
1)在执行函数时,函数的参数和函数内的局部变量及调用相关信息(局部变量,函数参数,返回数据,返回地址)的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限
2)(在函数内)声明变量/数组的方式,是在栈中分配内存。当调用完此函数返回的时候,栈空间自动被收回,其中的内容也就全部无效了。

在c++中malloc()函数分配空间的时候不能调用构造函数,由于类对象的建立是分配空间,构造结构和初始化三位一体故malloc()无法达到要求,它会返回一个非法对象的数据空间,同理,free也不会调用析构函数。

拷贝构造函数:

xxx(xxx&)参数是xxx&。拷贝构造函数的必要性,对象不同于基本数据,部分对象还申请了系统资源若s对象有一个资源,用它创建t,如果只是二进制内存空间的拷贝,那么t也拥有了这个资源,故会导致资源管理器的混乱。若未提供一个拷贝构造函数,编译器将会提供一个默认的拷贝构造函数,它只完成一个成员到另一个成员的拷贝,如果成员是类对象,则会调用它的拷贝或默认拷贝构造函数。

浅拷贝和深拷贝:当对象与资源联系(如堆,打开文件,占有硬件等),如果简单的进行拷贝(浅拷贝),会形成多个对象拥有一个资源故我们必须定义自己的拷贝构造函数,堆资源也进行拷贝(深拷贝)。

临时对象:

当函数返回一个对象时,要建立一个临时对象用以存放返回对象:被调用函数栈区->临时对象->main栈区。设a=f(n),当返回的临时对象赋给啊a后,临时对象就被析构了(故不要对其引用和取指针)。

构造函数用于类型转换:

如果目的类有以原始类为参数(只能一个)的构造函数,那么就可以。

静态成员和友元:

静态成员包括静态成员函数和静态数据成员

静态成员作用:让一个类的所有对象共享一个类成员(数据成员只初始化一次)。

在类对象的空间中并没有static数据成员的位置,它的空间不会随对象的产生而分配,或随对象的析构而消失,空间的回收也不在析构函数里完成。静态数据成员应该在程序开始运行就存在的。由于静态成员要实际分配地址空间,因而不能在类定义中写成定义,它也不能在头文件中类的声明外定义,会造成多个适用该头文件的源文件对其重复定义,静态成员也不能在main()函数之前的定义全局数据处定义,那会造成每个要使用该类的应用程序每次都要重新定义。故最好放在类定义的实现部分定义再合适不过。(前面都是废话:))

static数据成员的访问控制与一般成员差不多

注:静态数据成员只有属于哪个类的说法,没有属于哪个对象的说法。调用用::符号。不用.符号。

静态成员函数:与类联系,不与对象联系,访问用:: 符号,由于静态成员函数不与任何对象联系,故不能用静态成员函数对非静态成员作默认访问。

静态成员函数和非静态成员函数的根本区别是:静态成员函数没有this指针,而非静态成员函数都有指向当前对象的this指针。

友元部分略

类中的const数据也是在类外用::初始化 或者用初始化列表
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: