一、c++支持面向对象程序设计方法。面向对象程序设计具有十一个特征,下面是其中最重要的四个特征:
(I)抽象性,抽象性是指程序语言创建“黑盒”代码的能力
(II)封装性,封装性保证了接口和实现代码的相对独立性
(III)多态性,多态性使一个程序接口可以调用多种对象的方法。这有两种方式实现:前期绑定(编译时绑定函数方法)和后期绑定(运行时绑定函数方法)。
(IV)继承性,继承性同时保证了接口的相似性和特殊性。这通过子类继承父类来实现,子类拥有父类的接口方法,同时子类可以扩展父类的接口而拥有自己特有的接口。
二、c++的头文件:#include //现代c++头文件不使用.h扩展名
三、引入命名空间:using namespace std //现代c++使用命名空间
四、c++在程序块的任何地方都可申明局部变量。
五、c++不再有“默认为int类型”的特征,所以当函数有返回值时,必须名确申明返回值类型。
六、c++定义了内嵌的bool类型,bool类型的对象仅可以存储true和false,这两者是c++定义的关键字。允许把bool类型转换为整型,反之亦然。具体来讲,任何非0值都转换为true,而0转换
为false;也可以出现相反的情况:true转换为1,false转换为0.
七、c++的类。c++默认它的所有成员都是私有的。
(I)对象是现实的实体。
(II)类是现实实体的逻辑抽象
(III)对象的实例是计算机实体,存在于计算机内存中。一个程序块也是一个实体,所以c++中也将对象的实例称为对象。
c++中的所有函数都需要函数原型。
八、获得多态性:
(I)函数重载是c++获得多态性的途径之一
(II)运算符重载也可获得多态性,c++中的绝大多数运算符都可重载
(III)使用虚函数获得多态性,这种方式依赖于继承关系,他也是获得运行时多态性的途径.
九、c++中的关键字:c++区分大小写,c++关键字都是小写的
asm auto bool break case catch
char class const const_cast continue default
delete do double dynamic_cast else enum
explicit export extern false float for
friend goto if inline int long
mutable namespace new operator private protected
public register reinterpret_cast return short signed
sizeof static static_cast struct switch template
this throw true try typedef typeid
typename union unsigned using virtual void
volatile wchar_t while
十、在c++中结构的作用被扩展了,使它成为指定一个类的替代方法,默认时,结构的所有成员是公有的,而类是私有的。
结构的成员共享同一个名称.
十一、在c++中的联合也被扩展了,可以包含成员函数,默认是联合的所有成员是公有的。
联合的数据成员共享同一个地址.
c++有一种特殊类型的联合,即匿名联合,匿名联合没有类型名称,也不声明该联合的任何变量,但是,匿名联合告诉编译器它的数据成员共享同一个内存地址.然而,匿名联合的成员变量本身可被直接引用,无需常规的点运算符语法.匿名联合包含在函数体的内部.
十二、友元函数,准许非成员函数通过使用友元(friend)访问类的私有成员是可能的。要在类中申明友元函数,在类中包含它的原型,只需在它之前放上关键字friend。友元函数没有this
指针。
(I)派生类不继承友元函数
(II)友元函数不能有存储类标识符,即,它们不能被定义为静态的(static)和外部的(extern)
十三、内联函数,内联函数是c++的一个重要特征,通常用在类中。为了使一个函数在程序行里进行代码扩展而不被调用,只要在函数前面加上关键字inline即可。这个过程类似于使用宏代码。一般在短函数上使用inline关键字,这节省了运行时的调用过程,去掉了参数进栈和出栈的过程。在类代码内定义的函数通常被编译成内联函数.
十四、静态类成员。
(I)当把static置于一个成员变量的声明之前时,编译器被告知该变量只存在一个副本,且该类的所有对象将共享该变量。当在一个类内声明一个静态数据成员时,你不是在定义它
(即,没有为其分配存储空间),相反,必须在类外对静态数据成员提供全局定义,这可以为它分配内存。(用public限定的静态数据成员可以直接通过类名进行访问,例如:share::a=99;//share是类的名称)
(II)成员函数也可以被申明为静态的。第一、静态成员函数只能访问该类的其他静态成员(当然可以访问全局函数和数据);第二、静态成员函数没有this指针;第三、同一个函
数不能有静态和非静态两种版本,静态成员函数不可以是虚函数;最后它不能被申明为const或volatile。静态成员函数的应用是有限的,使用它的好处是在实际创建任何对象之前可以“预初始化”私有的静态数据。
十五、何时执行构造函数和析构函数。一般规则是,在申明对象时,对象的构造函数就被调用,对象销毁时,其析构函数就被调用。
(I)局部对象的构造函数在遇到对象申明语句时被执行,局部对象的析构函数按照与其构造函数相反的顺序执行。
(II)全局对象的构造函数在main()开始执行之前执行。全局构造函数在同一文件里按照它们的申明顺序执行,用户无法知道分布在几个文件里的全局构造函数的执行顺序。全局析构函数在main()结束之后按照相反的顺序执行。
十六、嵌套类,可以在一个类中定义另一个类,这样就创建了嵌套类。事实上,一个类声明定义了一个作用域,嵌套类只在封闭类的作用域中有效。
十七、局部类,可以在一个函数内定义一个局部类,该局部类只为该函数所知。局部类有一些限制条件:第一、所有成员函数必须在类声明内定义,局部类不能使用或访问它所属的函数的局部变量(除了局部类可以访问某些静态局部变量外,这些局部变量是在函数内声明或者是作为extern声明的);第二、不能在局部类里声明任何静态变量。
十八、向函数传递对象,对象能以和其他任何类型的变量相同的方式传递给函数。对象是通过使用标准的按值调用机制传递给函数的。
函数返回时,变量要被销毁,此时调用对象的析构函数,如果该析构函数释放动态分配的内存,则会产生负作用,导致返回的内存不可用.
函数返回对象,当对象被函数返回时,就自动生成一个临时对象来容纳返回值,函数返回的正是这个临时对象,值返回以后这个对象就被销毁。如果函数返回的对象有一析构函数释放动态分配的内存,则会产生副作用,导致返回的内存不可用。
十九、对象赋值,假设有两个相同类型的对象,可以把一个对象赋给另一个对象,这导致右边对象的数据拷贝到左边对象的数据中。
二十、按指针调用和按引用调用:
(I)按指针调用:void neg(int* i){i=-*i;} //i是一个指针,所以要用到指针运算符
(II)按引用调用:void neg(int& i){i=-i;} //i是一个引用参数,i是传递到函数中的实参的一个别名,这称为按引用调用
(III)可以使用基类指针指向派生类的对象
(IV)可以使用基类引用来引用派生类的对象
(V)引用的几种限制:不能引用别的引用,换句话说,不能获得引用的地址,不能创建引用数组,不能创建指向引用的指针,不能引用位域。如果引用变量不是类的成员、函数参数或返回值,在声明引用变量时,必须初始化它。此外,要禁止空引用。
(VI)函数可以返回一个引用,被返回的变量必须是一个全局变量。如果是一个局部变量,在函数返回时,该变量将被销毁,从而导致引用不可用。
二十一、c++的动态分配运算符:new和delete运算符。运算符new分配内存并返回指向分配内存开始处的指针。delete运算符释放new分配的内存。格式如下:
p_var=new type; //p_var是一个指针变量
delete p_var;
(I)释放数组运算符: int* p;
p=new int[10];
delete [] p;
(II)new的nothrow形式:int* p;
p=new(nothrow) int[32];
(III)new的放置形式: p_var=new(arg_list) type;
二十二、函数重载。函数重载提供了对编译时多态性的支持,也增加了灵活性和方便性。函数重载通过不同的函数签名完成。
重载构造函数的三个理由:为了获得灵活性,为了创建初始化和未初始化的对象,以及为了定义拷贝构造函数。
重载构造函数中一个较重要的形式是拷贝构造函数,定义一个拷贝构造函数可以帮助防止在用一个对象初始化另一个对象时可能出现的问题,比如内存问题等。
(I)拷贝构造函数只应用于初始化。例如,假定有一个类myclass,且y是myclass的一个对象,则下面的每条语句都做初始化操作:
myclass x=y; //y explicitly initializing x
func(y); //y passed as parameter
y=func(); //y receiving a temporary,return object
(II)拷贝构造函数的例子:
class myclass{
myclass();
myclass(const myclass &myinstance); /这是一个重载的拷贝构造函数,注意拷贝构造函数的参数,它是一个myclass类型引用参数,如果存在一个myclass类型的对象y,则可以这样初始化另一个myclass类型的对象x:myclass x(y);/
~myclass();
}
如果存在内存分配问题,就应该避免初始化时的按位拷贝。
二十三、默认的函数变元:
void myfunc(double d=0.0){… } //默认变元按变量初始化的方式指定。
二十四、函数重载和二义性:编译器不能在两个或两个以上的重载函数中作出正确选择,当这发生时,我们称之为具有二义性,具有二义性的程序无法编译。造成二义性的主要原因是c++的自动类型转换。
二十五、运算符重载:
(I)创建成员运算符: ret_type class_name::operator#(arg_list){//其中的#号是一个占位符,如果创建一元运算符arg_list为空,如果创建二元运算符arg_list是一个参数
//operator
return ret_type;
}
(II)当使用二元成员运算符时,运算符左边的操作数产生了对运算符函数的调用,右边的操作数作为参数传递给函数。
(III)使用非成员运算符函数(它通常是一个类的友元函数,所以不会隐式传递this指针),必须显式传递参数,左操作数通过第一个参数传递,右操作数通过第二个参数传递。
(⒈)new/new[]/delete/delete[]作为操作符可以被重载
(⒉)重载[]操作符,重载[]时把它作为二元运算符
(⒊)重载()操作符,重载()时,实际上用户不是创建一种调用函数的新方法,而是创建可以传递任意多个参数的运算符函数。
(⒋)重载->操作符,重载->时,必须返回一个激活该函数调用的对象的指针
(⒌)逗号运算符也可以重载
二十六、继承。继承是扩展功能的好方法。继承采用下面的通用形式:
class derived_class_name:access base_class_name{
//body of class
};
access是访问限定符,必须是public/protected/private,如果没有提供访问限定符,当派生类是class时默认为private,当派生类是struct时默认为是public
(⒈)当基类的访问限定符是public时,基类的所有公有成员将成为派生类的公有成员,基类的所有保护成员成为派生类的保护成员;然而,基类的私有成员将总是基类所私有,不能被派生类访问。
(⒉)当基类的访问限定符是private时,基类的所有公有成员和保护成员将成为派生类的私有成员。
(⒊)继承和保护成员。可以用protected关键字创建类成员,申明为proected的成员不能被外部代码所访问,但仍然可以被派生类继承和访问,这给继承机制提供了更大的灵活性。
①派生类以public方式继承基类时,基类的保护成员成为派生类的保护成员
②派生类以private方式继承基类时,基类的public成员和protected成员成为派生类的私有成员
③派生类以protected方式继承基类时,基类的public成员和protected成员成为派生类的保护成员
(⒋)c++的继承机制可以继承多个基类,继承形式如下:
class derived:public base1,public base2{
//body of class,确保对每个基类使用一个访问限定符
}
(⒌)构造函数、析构函数和继承。涉及继承时,有两个问题要解决:第一,什么时候调用基类和派生类构造函数和析构函数;第二,怎样将参数传递到基类的构造函数?
①一个派生类总是包含于基类的,依据这个理解,当创建一个派生类对象时,首先调用的是基类的构造函数,然后才是调用派生类的构造函数;当销毁一个派生类对象时,
首先调用的是它的析构函数,然后才调用基类的析构函数。如果存在多层次继承,则构造函数按照派生的顺序执行,而析构函数则按照相反的顺序执行。
②当有多个基类时,按照基类列表顺序从左至右依次调用基类的构造函数,销毁时则按照从右至左的顺序依次调用基类的析构函数。
③把参数传递给基类的构造函数:利用派生类构造函数声明的扩展形式可以把参数传递给一个或多个基类的构造函数,其扩展形式如下:
derived_class::derived_constructor(arg_list):base1(arg_list),base2(arg_list),base3(arg_list){
//body of constructor
}
但要理解一点:基类的构造函数的参数是通过派生类的构造函数的参数列表向基类传递的;
(⒍)c++支持访问声明以满足下列情况:即继承类的大多数成员是私有的,而少数成员继续保持公有或保护状态。
这可以通过准许访问方式实现:第一、可以使用using语句,这是首选方式;第二、在派生类中使用访问声明,形式如下:
class derived_class:private base{
…; //the private list of member
public:
base::base_of_member;
protected:
base::base_of_member;
}
(⒎)在二重或多于二重的继承中使用虚基类(virtual关键字,virtual在其他的关键字之前),可以保证在派生类中只有一个基类的副本。注意,基类和派生类本身不是虚类,只是在继承是使用了虚继承的方式。普通基类和虚基类的唯一不同之处在于:在一个对象多次继承基类时将出现何种情况:如果使用虚基类,该对象中将只出现一个基类;否则,对象中将出现多个基类副本。
二十七、组合使用继承和虚函数可以实现运行时多态性
(⒈)虚函数是一个成员函数,该成员函数在基类内部声明并被派生类重新定义,为了创建虚函数,应在基类中该函数的声明之前加上virtual关键字(注意virtual关键字在访问声明关键字后面和返回类型声明的前面),当继承包含虚函数的类时,派生类将重新定义该虚函数以符合自己的需要。注意,当“正常”访问虚函数时,虚函数就象所有其他类型的类成员函数一样。
通过虚函数实现多态性的原理:声明为基类类型的指针变量可以存储基类对象的指针和派生类对象的指针。
通过基类引用调用虚函数时,其多态性也是可用的。一个引用是一个隐含的指针,所以一个基类引用可以用来访问基类的某个对象或任何从该基类派生的对象。
①无论虚函数被继承多少次,虚函数仍然是虚的
②虚函数是分层的,当某个派生类不能覆盖虚函数时,使用按照派生顺序的逆序找到第一个重新定义的函数进行访问。
③纯虚函数是没有在基类中定义的的虚函数,在派生类中必须给出纯虚函数的定义。在基类中声明纯虚函数的方式如下:
access:
virtual type function_name(arg_list)=0;
二十八、抽象类:至少包含一个纯虚函数的类称为抽象类,抽象类没有明确的定义,因此不能创建抽象类的对象,抽象类必须被继承。但可以创建指向抽象类的指针,这配合派生类来实现多态性。
二十九、前期绑定与后期绑定,前期绑定发生在编译过程,后期绑定发生在运行过程。后期绑定能灵活的处理不同的状态,但运行速度较慢。
三十、使用模板,可以创建通用的函数和类。创建通用函数时要使用模板(template)关键字,模板的具体细节由编译器根据具体情况决定;其实现如下:
template