资源描述
1、 const:用const 定义常量。
2、 内置函数:用inline修饰的函数称为内联函数、内嵌函数(减少开销、提高效率。)
3、 关键字union定义联合函数。
4、 在C语言中,用malloc( )和free( )两个函数来动态分配和释放内存。
在C++中,用new和delete两个运算符来动态分配和删除存储块。用new算子时要指明数据类型,new算子分配一个足以放下指明类型对象的存储空间,然后返回该存储块的首地址。
结构不仅可以含有不同类型的数据,而且还可以含有函数。
结构包括数据成员和成员函数。
对结构成员的访问:1)结构变量名.成员名 2)指针类型结构变量—>成员名
结构成员分两类:1)私有成员(private)只能被结构中的其他成员访问 2)公有成员(public)既可以被结构中的其他成员访问;也可以被结构外的其他成员访问。(缺省时,默认为公有的。)
在C语言中:结构体不允许有成员函数
在C++中:结构体允许有成员函数
类与结构体的区别:除关键字不同外(class,struct),唯一的区别是。结构的成员在默认情况下是公有的,而类的成员在默认情况下是私有的。
类的声明格式:
class 类名{
private:
私有数据成员和成员函数
protected:
保护数据成员和成员函数
public:
公有数据成员和成员函数
};
类的成员分为三类,缺省时,默认是私有的。
私有成员(private):只能被该类的成员函数访问;类外函数通过该类公有成员函数访问私有成员
保护成员(protected):既能被该类的成员函数访问;还可被该类的派生类的成员函数访问
公有成员(public):既能被该类的其他函数访问;也可被类外的其他函数访问
如果把private段放在最前面:关键字private可以省略;否则不可以省略
protected和pubilc段不论出现在何处均不可以省略关键字。
数据成员可以是任何数据类型,但是不能用extern(外部)、auto(自动)、register(寄存器)指定其存储类型;不能在类声明中给数据成员赋值;不同类的成员可以同名。
成员函数的定义:1)成员函数不仅要在类体内被说明,还需要在类外做定义 2)定义格式
返回类型 类名::函数名(参数表){…//函数体} 3)成员函数的定义方式:在类声明中给出函数原型,在类声明的外面定义函数;将成员函数定义为内置函数,一提高执行效率。
class point{
private:
int x, y;
public:
void setpoint(int , int);
int getx( );
int gety( );
};
void point::setpoint(int a, int b)
{x=a; y=b;}
int point::getx( )
{return x;}
int point::gety( )
{ return y;}
在类声明外定义成员函数时必须在函数名前加 类名::
成员函数若有参数,要有完整的参数说明
成员函数的返回类型,应该与函数原型声明的相同。
显示定义:1)在类声明的外面定义成员函数 2)在函数定义前加inline
inline void point::setpoint( int a, int b){x=a; y=b;}
类和对象是抽象和具体的关系。
类是对一组对象的抽象,这组对象具有相同的属性结构和操作行为
对象是类的一个实例,将类作为创建对象的样板。
类实际是一种新的数据类型,使用这种类型之前,先要在源程序中说明。说明中的代码不会在内核中运行,只在编译时存在。
对象是程序运行时存在的实体,和变量一样,对象占有内存空间,程序的计算任务都是通过对象调用它相应的操作行为来完成。对象是类的实际变量。
类相当于一种类型,并不接受和存储具体的数值,只是生成对象的一种样板,只有定义对象后,系统才给对象分配空间,并通过对象调用类的成员函数。
若在声明类的同时定义对象,对象是一种全局变量。若在函数中使用时才定义对象,对象是局部变量。
对象成员的访问:1)访问格式: 对象名.数据成员名;对象名.成员函数名
2)访问说明:外部函数不能访问类的私有成员;如果定义的是指针类型对象使用 —> 访问类成员
类的作用域:在类的声明中,一对大括号所形成的作用域称为类的作用域。在类的作用域中,一个成员可以引用该类的其它成员;在类的作用域外,私有成员不能被访问,实现类的封装性。
构造函数和析构函数是两个特殊的成员函数。构造函数用于创建对象,并对对象初始化,析构函数用于撤销类对象,回收存储空间,并做一些善后工作。
构造函数可以重载:可以有参数,也可以没有参数;在生成对象时,系统要根据参数的情况决定调用哪一个构造函数。
带参数的构造函数:创建对象时将实参传递构造函数,以初始化对象使得各对象的数据的初始值不同
不带参数的构造函数:对数据成员的初始化,取决于构造函数体中对哪些数据成员进行赋值,而且用此结构函数构造的所有对象的初始值都相同。
拷贝构造函数:当用一个已经存在的对象构造一个新的对象时,系统自动调用拷贝构造函数来创建新的对象,并把老对象的数据成员的数值拷贝给新的对象。
拷贝构造函数的声明形式: 类名(const 类名&对象名);
拷贝构造函数的定义形式: 类名(const 类名&对象名){……//函数体}
如果没有定义拷贝构造函数,系统就会产生一个缺省的拷贝构造函数,用已经存在的对象复制一个新的对象,并对数据成员逐位拷贝。
拷贝构造函数没有返回值。
当类中成员是指针类型时,可能出错。
一般情况下,不必定义拷贝构造函数。但是如果构造函数中存在需要动态分配内存数据成员,必须定义拷贝构造函数。
析构函数:在类定义体中,与类同名、并在前面加“~”的成员函数。
释放对象在构造时分配的资源;关闭被构造函数打开的文件,释放动态内存
对象的生命周期结束时,由系统自动调用,调用的顺序与构造函数相反。
析构函数的说明:析构函数的名字以波浪符“~”开始,其余部分与类名相同
不能指定任意返回类型,甚至void;析构函数不能带参数;一个类只有一个析构函数,省略时,编译器自动创建一个缺省析构函数 ~complex( ){}
对象撤销时,编译系统自动调用析构函数;对于非动态对象,当程序执行离开其作用域时自动被撤销,对于静态对象,只有执行delete操作后才能被撤销
析构函数必须说明为公有成员,因撤销对象是在类外进行的
若析构函数在创建对象时申请了空间(new);析构函数需要做回收空间的工作(delete)
this指针:this指针是一个隐含的指针。
每个成员函数都有一个this指针变量,this指针指向该成员函数所属的对象
当对象调用所在类的成员函数时;成员函数的this指针便指向该对象;通过this指针知道自己属于哪一个对象;也可以通过this指针访问该对象的成员。
向函数传递对象:使用对象作为函数参数;是通过传值调用,半对象的拷贝而不是对象本身传给函数;函数中对形参对象的修改,不影响实参对象本身
使用对象指针作为函数参数;将实参对象的地址传递给函数的形参,函数中可以改变形参对象的值。
对象指针作为函数参数:使用对象指针作为函数参数时,调用函数的对应实参应该是某个对象的地址值。由于不进行副本的拷贝,可以减少时空开销,提高运行效率。
对象引用作为函数参数:使用对象引用作为函数参数时,调用函数的实参对象就会被形参对象引用,也就是形参对象代表了实参对象。
由于不进行副本的拷贝,可以减少时空开销,提高运行效率。
在函数里改变形参即改变实参
若只想引用实参的数据,而不愿意改变它 void sqr_it( const tr &ob)
静态成员:在一个类中,可以将一个数据成员说明为静态成员static
静态成员的特性是:无论这个类建立了多少个度一项,这些对象的静态成员都只有一个数据拷贝,即所有对象都共享静态成员。
静态成员的说明:静态数据成员是属于类的,而不象普通数据成员属于对象,访问方式为
类名::静态数据成员
静态数据成员不能在类中初始化,一般在类外和main函数之间初始化,
例如:int student::count=0; 缺省时被初始化为0
静态数据成员在编译时创建并初始化,在该类的任何对象建立前就存在,它不属于任何对象
静态数据成员用于,定义类的各个对象所公有的数据,比全局变量更安全。
在定义中,用static说明的成员函数称为静态成员函数。
静态成员函数属于整个类,不属于某一个对象,由该类所有对象共享
静态成员函数的调用格式:
类名::静态成员函数名(参数表)
对象名.静态成员函数名(参数表)
对象指针—>静态成员函数名(参数表)
静态成员函数一般用于访问,同一个类中的静态数据成员,以维护类中对象共享的数据,或全局变量
静态成员函数一般不访问非静态成员,如需访问非静态数据成员,应将对象作为参数,通过对象名访问该对象的非静态成员
Static void display(small_cat &w)
{cout<<”The small_cat weights ”<<w.weight<<”pounds\n”;}
静态成员函数可以定义成内联函数;静态成员函数也可以类外定义,前面不再用static修饰
使用静态成员函数的一个原因,在建立任何对象之前,可用它访问静态数据成员。普通成员函数不能实现此功能
静态成员函数没有this指针,因为它不支特定的对象相联系,调用时使用如下格式较好
类名::静态成员函数名(参数表)
对象数组:每一个数组元素都是对象的数组。
如果在类中没有自定义的结构函数,对象数组由系统提供的缺省构造函数建立,赋值前每个对象数组元素含有未定义的数据
如果要为数组元素初始化,需要设计类的构造函数,不带参数,带参数,带缺省参数
对象数组元素的初始化:若要求各个元素的初始值相同,应该定义不带参数的构造函数,或者带缺省参数值的构造函数
如以前各个元素的初值不同,需要定义带参数的构造函数,参数不可以由默认值,在定义对象数组时,通过初始值表赋值。
对象指针:指向对象的指针变量为对象指针。
Struct person
{ 结构变量成员的访问
char* name; person charlie
int height; charlie.height
int weight; person* wang = new person()
int age(); wang -> height
};
用对象指针引用对象数组
exe *p //声明对象指针
exe ob[ 2 ]; //声明对象数组
p = ob; //把第一个对象的地址赋给p,等价于 p=&ob[ 0 ];
p++; ` //p指向第二个对象
this指针举例:
class abc{
private:
char a;
int b;
public:
void init(char mea int mb) //void init(abc *this, char ma, init mb)
{a = ma; b = mb;} //{ this ->a=ma; this->b=mb;}
};
main( )
{
abc ob;
ob.init(‘x’, 12) //ob.init(&ob, ‘x’, 12)
return 0;
}
向函数传递对象:使用对象作为函数参数;是通过传值调用,把对象的拷贝而不是对象本身传给函数;函数中对形参对象喜爱那个的修改,不影响实参对象本身
使用对象指针作为函数参数,将实参对象的地址传给函数的形参,函数中可以改变形参对象的值。
对象指针作为函数参数:使用对象指针作为函数参数时,调用函数的对应实参应该是某个对象的地址值。由于不进行副本的拷贝,可以减少时空开销,提高运行的效率。
静态成员:在一个类中,可以讲一个数据成员说成是静态成员static。
静态成员的特性是:无论这个类建立了多少个对象,这些对象的静态成员都只有一个数据拷贝,即所有对象都共享静态成员。
为何需要友元?
有时候需要在类的外部访问类的私有成员,C++提供了友元函数的机制。
一个类的友元函数可以访问这个类的所有成员,包括公有的和私有的成员。
友元函数可以不属于类的一般函数,也可以是另外一个类的成员函数,还可以是整个类。
友元函数:
一个类的友元函数不是类的成员函数,它是独立于类的外部函数;可以访问这个类的所有私有和保护成员
在类定义中声明友元函数,需要在函数名前加上关键字friend
如:friend void disp( girl & ); 友元声明可放在公有或私有部分;友元函数可以定义在类内或类外。
友元函数的说明:
因为友元函数不是类的成员函数,在类体外定义时不要加 类名::
友元函数一般带有所属类的入口参数,通过入口参数向友元函数传递类的对象,访问该类对象的成员时 对象.成员名 或 对象指针->成员名
一个函数可以成为多个类的友元函数,因而可以访问多个类的成员。
友元函数的说明:
一个类的成员函数作为另一个类的友元函数时,必须先定义成员函数所在的类,然后在其它类中声明该友元函数时,要加上成员函数所在的类名 friend void boy::disp(girl &);
类girl必须有向前引用 class girl; 函数disp( )将girl &作为参数; 而类girl要在以后才被定义
友元类:
一个类可以说明是另一个类的友元; 友元类的所有成员函数均成为这个类的友元函数
class Y{ //…. };
class X{ //….
friend Y; //Y的所有成员函数均为X的友元函数
//….};
友元类的说明:
友元关系是单向的,不具有交换性和传递性。
如果类X是类Y的友元,那么类Y不一定是类X的友元,除非在类X中声明类Y是友元
若X是Y的友元,Y是Z的友元,那么类X不一定是类Z的友元。
类成员初始化的说明:
当调用构造函数X::X( )时,首先按对象成员在类中定义的顺序,依次调用它们的构造函数。将这些对象成员初始化后,才执行X的构造函数,即函数体内的程序语句。
析构函数的调用顺序与此相反。
派生类与继承:
派生类的基本概念:派生类的声明和使用方式;派生类的构造和析构函数。
调整基类成员在派生类中的访问属性
多重继承
赋值兼容规则
继承性:继承是面向对象程序设计的一个重要特性,它允许在既有类的基础上创建新的类,新类可以从一个活多个既有类中继承数据和函数,并可以加进新的数据和函数,从而形成类的层次。
基类与派生类:
用来派生新类的类称为基类(或父类)
由基类派生的新类称为派生类(或子类)
派生类继承了基类的特性;基类的数据成员和成员函数,除了基类的析构函数和构造函数不可继承
派生类可以定义自己的新特性;增加需要的数据成员和成员函数
派生类还可以做些调整;重新定义基类中已有的成员函数,改变继承得来的基类成员的属性
单一继承和多重继承:
在C++语言中,一个派生类可以从一个基类派生,也可以从多个基类派生.
从一个基类派生时;派生类继承一个基类的成员,称为单一继承
从多个基类派生时;派生多个基类的成员,称为多重继承
派生类的声明:
单一继承的格式:
class <派生类名>:<继承方式><基类名>
{
private:
members; //派生类新定义成员
protected:
members;
public:
members;
};
派生类的继承方式:
私有继承 private:
保护继承 protected:
公有继承 public:
不同的继承方式导致原来具有一定属性的基类成员,在派生类中的访问属性页有所不同。
继承性:
继承是面向对象程序设计的一个重要特性,它允许在既有类的基础上创建新的类,新类可以从一个或多个既有类中继承数据和函数,并可以加进新的数据和函数,从而形成类的层次。
私有继承下基类成员的访问属性:
私有派生类对基类成员的访问:基类的私有成员,既不能被外部函数访问;也不能被派生类成员访问。
基类的公有成员,可以被派生类成员访问;因此,派生类可以通过基类的公有成语那函数访问这些基类的私有成员。
外部函数访问私有派生类继承的基类成员
基类的公有成员:在派生类中成为私有的;虽然外部函数不能访问;但是派生类成员可以访问。
公有继承:
公有继承的特点是:基类的公有和保护成员,将成为派生类的成员,它们保持原有的状态;公有和保护
基类的私有成成员,在派生类中不可直接访问。
公有继承下基类成语那的访问属性:
基类的公有成员在派生类中仍是公有的,外部函数和派生类成员可直接访问
基类的私有成员即使被公有继承,既不能被外部函数访问,也不能被派生类成员访问;但是,外部函数和派生类可以通过基类的公有成语那函数来访问这些基类的私有成员。
派生和继承的说明:
无论派生以私有或公有方式继承基类成员,派生类都不可以直接访问基类的私有成员。
在派生类中定义域基类同名的成员:如果派生类定义了与基类同名的成员,称派生类的成语那覆盖了基类的同名成员
若要、在派生类中使用与基类同名的成员,可以显式的使用作用域运算符 类名::成员
引入保护成员的作用:派生类要使用基类的私有成员,只能通过调用基类的公有成员函数来访问,当派生类要频繁访问基类的私有成员时,上述约束不方便。
为了让派生类能够直接访问基类的私有成员,可将基类的私有成员定义为保护成员.
基类的保护成员的访问属性:
保护成员既能被所在类成员函数访问,还可以被该类的派生类成员函数访问.
公有继承时, 基类的保护成员在派生类中仍是保护的; 外部不能访问,但是派生类成员可以访问
私有继承时, 基类的保护成员在派生类中仍是私有的; 外部不能访问,但是派生类成员可以访问
派生类的构造函数:
在建立派生类的对象时, 不仅要初始化自己新添加的数据成员, 还需要初始化从基类继承得来的数据成员
基类的构造函数不能被派生类继承, C++提供一种机制,使得在创建派生类对象时, 能够调用基类的构造函数来初始化基类的数据成员。
派生类的构造函数包含两个功能, 既初始化自己的数据成员, 又调用基类的构造函数, 以初始化基类的数据成员
派生类构造函数的一般格式
<派生类名> (<派生类构造函数总参数表>) :<基类构造函数> (<参数表>)
{
//派生类中构造函数体
}
派生类构造函数的调用顺序:创建派生类对象时,派生类构造函数的顺序是:
先调用基类的构造函数, 再执行派生类构造函数体中的语句。
派生类的析构函数:
由于基类的析构函数也不能被继承,因此在撤销派生类对象时,系统先自动执行派生类的析构函数,然后再调用基类的析构函数。其顺序与执行派生类构造函数时的顺序相反。
先执行派生类的析构函数,释放在派生类够在函数体内动态分配的资源
再执行基类的析构函数,释放在基类构造函数体内动态分配的资源。
若派生类中含有对象成员:
派生类构造函数的调用顺序:1)调用基类的构造函数 2)调用对象成员类的构造函数 3)执行派生类构造函数体中的语句。
二义性:
一般来说,在派生类中对基类成员的访问应该是唯一的。但是,在多重继承情况下,可能会出现对基类成员中某个成员的访问不唯一的情况,即对基类成员访问的二义性的问题。
同名成员的二义性:
在多重继承中,如果不同基类中有同名的函数,则在派生类中就有同名的成员被继承,对这种同名成员的访问就会造成二义性。
派生类构造函数的执行顺序:
先执行所有基类的构造函数;再执行派生类本身构造函数;
处于同一层次的各基类构造函数的执行顺序,取决于定义派生类时指定各基类的顺序,与派生类构造函数的成语初始化列表中的各项顺序无关。
多重继承派生类的构造函数说明:
在多重继承下,派生类的构造函数与单一继承的派生类构造函数相似,它必须调用派生类所有基类的构造函数。
派生类的参数个数必须包含完成所有基类初始化所需要的参数个数。
析构函数的执行顺序刚好与构造函数的执行顺序相反。
为何需要虚基类?
如果一个派生类从多个基类派生,而这些直接基类又有一个共同的基类,则在派生类的内存中存在该基类的多个副本,在对从该基类继承而来的成员进行访问时,就可能产生二义性。
C+=语言允许在派生类中只建立公共基类的一个副本。
方法是将直接基类的共同基类设置为虚基类。这时,从不同路径继承来的该基类成员在派生类的内存中只拥有一个副本,有关公共基类成员访问的二义性问题就不存在了。
虚基类:
引进虚基类的目的,是为了解决二义性的问题
当公共基类被继承时,在该基类的访问控制前加上关键字virtual把它说明成虚基类。
若把某基类声明为虚基类,当它被重复继承时,在派生类对象中只有一个副本;否则,将出现多个该基类成员的副本。
虚基类的说明格式; virtual<继承方式><基类名>
Virtual是虚基类的关键字,虚基类的说明是用在定义派生类时,写在派生类名的后面。
当一个类有虚基类时,编译系统为该类对象定义一个指针成员,使它指向虚基类的子对象,该指针被称为虚基类指针。
虚基类的构造:
派生类与基类之间的继承关系可以用一个有向无环图(DAG)表示。
有向无环图的一个类,可能是虚基类,也可能是非虚基类
在派生类的对象中,同名的虚基类只产生一个子对象,每个非虚基类产生各自的子对象
虚基类的构造函数按继承的顺序调用,先左后右,自上而下
建立虚基类子对象时,任一虚基类的构造函数仅被调用一次。
不同继承方式的基类和派生类特性
继承方式
基类特性
派生类特性
公有继承
public
public
protected
protected
private
不可访问
私有继承
public
private
protected
private
private
不可访问
保护继承
public
protected
protected
protected
private
不可访问
派生类的构造函数:
在碱类派生类的对象时,不仅要初始化自己新添加的数据成员,还需要初始化从从基类继承得到的数据成员
基类的构造函数不能被派生类继承,C++提供了一种机制,使得在创建派生类对象时能够调用基类的构造函数来初始化基类的数据成员。
派生类的构造函数包含两个功能,既初始化自己的数据成员,又基类的构造函数,以初始化基类的数据成员。
派生类构造函数的调用顺序:
创建派生类对象时,派生类构造函数的调用顺序是:先调用基类的构造函数,再执行派生类构造函数体中的语句。
派生类的析构函数:
由于基类的析构函数也不能被继承,因此在撤销派生类对象时,系统先自动执行派生类的析构函数,然后在调用基类的析构函数。其顺序与执行派生类构造函数时的顺序相反。
先执行派生类的析构函数,释放在派生类函数体内动态分配的资源
再执行基类的析构函数,释放在基类构造函数体内动态分配的资源。
派生类析构函数的调用顺序:
调用基类的析构函数;调用对象成员类的构造函数;执行派生类构造函数体的语句。
展开阅读全文