面向对象程序设计——C++
知识点专栏
第一章
面向对象程序设计4个基本特征:抽象,封装,继承,多态。
第二章
using namespace std 是使用命名空间std ,使用命名空间std可保证对C++标准库每一个特性都是唯一,不至于发生命名冲突。
用cin和cout输入或输出数据时,可以用不同的方式显示数据。此时用到操作符dec,hex,oct
cout<<hex<< i <<‘ ‘<<dec <<i<<‘ ‘<< oct <<i<<endl;
const修饰符(定义常量)
1.const的作用与#define相似,const消除了#define的不安全性。
2.const与指针的结合,可以归纳为三种
(1)指向常量的指针(改地址吧)
是指一个指向常量的指针变量。
在指针定义语句的类型前加const,表示指向的对象是常量。
const char *name=“chen”;
name[3]=‘a’;//error
name=“zhang”;//ok
(2)指针常量(常指针)(改内容)
把指针本身,而不是它指向的对象声明为常量。
int * const pc=&b;
说明:pc是常量,不能做为左值进行操作,但是允许修改间接访问值,既 *pc 可以修改。
例:char * const pc=“chen”;
pc[3]=‘a’;
*pc=‘b’;
*(pc+3)=‘a’;
pc=“zhang”; //error
(3)指向常量的常指针(什么都不能改)
指针本身不能改变,它所指向的值也不能改变。
注意:定义一个指向常量的指针常量,必须在定义时进行初始化。
const char *const name=“chen”;
name[3]=‘a’; //error
name=“zhang”;//error
内置函数
1)内置函数在被调用之前必须进行完整的定义,通常写在主函数的前面。
2)在内置函数体内一般不能有循环语句和开关语句。
3)在类说明体类定义的函数都是内置函数。
4)当函数体内语句少,而使用频繁时可以考虑用内置函数。
缺省函数
1)在函数原型中,所有取默认值的参数都必须出现在不取默认值的参数的右边。
int fun (int i,int j=5,in k); //error
int fun (int i ,int k, int j =5);//ok
2)在函数调用时,若某个参数省略,则其后的参数皆应省略而采用默认值,不允许某个参数省略后,再给其后的参数指定参数值。
spe( ,25);//error
函数重载
参数个数不同或参数类型不同的函数,那么这样的几个函数可以使
作用域运算符::
如果希望在局部变量的作用域内使用同名的全局变量,可以在此变量前加::
new 和Delete (分配内存和释放内存)
new和delete优点:
1)new可以自动计算所要分配内存的类型的大小。
2)new能自动返回正确的指针类型,不必对返回指针进行类型转换。
3)可以用new将分配的对象初始化
4)new和delete都可以被重载。
new可在简单变量分配内存的同时,进行初始化。
基本形式:
指针变量名 = new 类型(初值)
引用
- 数据类型 &引用名=已定义的变量名;
int i=1;
int &j=i ;
- 声明一个引用,不是新定义了一个变量,它只表示该引用名是已定义的变量名的一个别名,它本身不是一种数据类型,因此引用本身不占存储单元
- 可以为指针变量建立引用:
int *a; int *&p=a;
int b=8; p=&b;
- 对void进行引用是不允许的
void &a=…;//error
- 不能建立数组的引用
int a[10];
int &ra[10]=a;// error
- 有空指针,无空引用
int &i=NULL;//error
-
以引用返回函数值,定义函数时需要在函数名前加&。。
-
(1)在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递中,解决大块数据或对象的传递效率和空间不如意的问题。
(2)用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,保证了引用传递的安全性。
(3)引用与指针的区别是,指针通过某个指针变量指向一个对象后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。
第三章
有关类的重点说明
系统默任的属性是private.
不能在类声明中给数据成员赋初值.
访问属性
类成员有三种访问属性:公有(public)、私有(private)和保护(protected)。
- 说明为公有的成员不但可以被类中成员函数访问;还可在类的外部,通过类的对象进行访问。
- 说明为私有的成员只能被类中成员函数访问,不能在类的外部,通过类的对象进行访问。
- 说明为保护的成员除了类本身的成员函数可以访问外,该类的派生类的成员也可以访问,但不能在类的外部,通过类的对象进行访问。
构造函数
- 构造函数是一种特殊的成员函数,它主要用于为对象分配空间,进行初始化。
- 构造函数具有一些特殊的性质:
(1) 构造函数的名字必须与类名相同。
(2) 构造函数可以有任意类型的参数,但不能指定返回类型。它有隐含的返回值,该值由系统内部使用。
(3) 构造函数是特殊的成员函数,函数体可写在类体内,也可写在类体外。
(4) 构造函数可以重载,即一个类中可以定义多个参数个数或参数类型不同的构造函数。
(5) 构造函数被声明为公有函数,但它不能像其他成员函数那样被显式地调用,它是在定义对象的同时被调用的。
- 通常,利用构造函数创建对象有以下二种方法:
(1) 利用构造函数直接创建对象.其一般形式为:
类名 对象名[(实参表)];
这里的“类名”与构造函数名相同,“实参表”是为构造函数提供的实际参数。
(2) 利用构造函数创建对象时,通过指针和new来实现。其一般语法形式为:
类名 *指针变量 = new 类名[(实参表)];
例如:
Date *date1=new Date(1998,4,28);
就创建了对象(*date1)。
析构函数
析构函数也是一种特殊的成员函数。它执行与构造函数相反的操作,通常用于撤消对象时的一些清理任务,如释放分配给对象的内存空间等。
析构函数有以下一些特点:
① 析构函数与构造函数名字相同,但它前面必须加一个波浪号(~);
② 析构函数没有参数,也没有返回值,而且不能重载。因此在一个类中只能有一个析构函数;
③ 当撤消对象时,编译系统会自动地调用析构函数
自引用指针this
- 在每一个成员函数中都包含一个特殊的指针,this指针
- 保证成员函数引用的数据成员是指定对象的数据成员
- this指针是指向本类对象的指针,它的值是当前被调用的成员
函数所在对象的起始地址 - this指针是隐式使用的,它是作为参数被传递给成员函数的
• this指针是一个const指针,不能在程序中修改它或给它赋值.
• this指针是一个局部数据,它的作用域仅在一个对象的内部.
‘
静态数据成员
- 在一个类中,若将一个数据成员说明为static,这种成员称为静态数据成员。
- 与一般的数据成员不同,无论建立多少个类的对象,都只有一个静态数据的拷贝。从而实现了同一个类的不同对象之间的数据共享。
定义静态数据成员的格式如下:
static 数据类型 数据成员名;
-
静态数据成员属于类,可以使用类名::访问静态数据成员.
-
静态数据成员不能在类中进行初始化. 一般在类声明后,main()之前.
-
静态数据成员在编译时创建并初始化,公有的静态数据成员可以在对象定义之前被访问.
-
私有静态数据成员不能被类外部函数访问,也不能用对象进行访问.
-
静态成员函数可以定义成内嵌的,也可以在类外定义,在类外定义时,不用static.
-
静态成员函数无隐含的this指针.
友元
-
友元既可以是不属于任何类的一般函数,也可以是另一个类的成员函数,还可以是整个的类。
-
友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但它可以访问该类的所有对象的成员,包括私有成员、保护成员和公有成员。
-
一个类的成员函数也可以作为另一个类的友元,这种成员函数不仅可以访问自己所在类对象中的所有成员,还可以访问friend声明语句所在类对象中的所有成员。
第四章
调整访问属性的方法
调整访问属性的方法是同名成员法和访问声明法
-
保护成员可以被本类的成员函数访问,
也可以被本类的派生类的成员函数访问,
而类外的任何访问都是非法的,既它是半隐蔽的. -
在派生类中,从基类继承来的成员可以按访问属性划分为四种:
不可直接访问的成员
public (公有成员)
protected (保护成员)
private (私有成员)
在基类中的访问属性 | 继承方式 | 在派生类中的访问属性 |
---|---|---|
private | public | 不可直接访问 |
private | private | 不可直接访问 |
private | protected | 不可直接访问 |
public | public | public |
public | private | private |
public | protected | protected |
protected | public | protected |
protected | private | private |
protected | protected | protected |
公有继承
基类成员 | private | public | protected |
---|---|---|---|
内部访问 | 不可 | 可 | 可 |
对象访问 | 不可 | 可 | 不可 |
私有继承
基类成员 | private | public | protected |
---|---|---|---|
内部访问 | 不可 | 可 | 可 |
对象访问 | 不可 | 不可 | 不可 |
保护继承
基类成员 | private | public | protected |
---|---|---|---|
内部访问 | 不可 | 可 | 可 |
对象访问 | 不可 | 不可 | 不可 |
派生类构造函数和析构函数的执行顺序
通常情况下,当创建派生类对象时,首先执行基类的构造函数,随后再执行派生类的构造函数;
当撤消派生类对象时,则先执行派生类的析构函数,随后再执行基类的析构函数。
虚基类
在C++中,如果想使这个公共的基类只产生一个拷贝,则可以将这个基类说明为虚基类,说明方法是在此类的派生类中使用关键字virtual.
- 建立一个对象时,如果这个对象中含有从虚基类继承来的成员,则虚基类的成员是由最远派生类的构造函数通过调用虚基类的构造函数进行初始化的。该派生类的其他基类对虚基类构造函数的调用都自动被忽略。
- 若同一层次中同时包含虚基类和非虚基类,应先调用虚基类的构造函数,再调用非虚基类的构造函数,最后调用派生类构造函数;
- 对于多个虚基类,构造函数的执行顺序仍然是先左后右,自上而下;
- 对于非虚基类,构造函数的执行顺序仍是先左后右,自上而下;
- 若虚基类由非虚基类派生而来,则仍然先调用基类构造函数,再调用派生类的构造函数
第五章
多态
多态分为:编译时的多态和运行时的多态。
编译时的多态是通过静态联编来实现的。静态联编就是在编译阶段完成的联编。编译时多态性主要是通过函数重载和运算符重载实现的。
运行时的多态是用动态联编实现的。动态联编是运行阶段完成的联编。运行时多态性主要是通过虚函数来实现的。
运算符重载
-
通过创建运算符函数operator( )来实现。(可以是类外的运算符重载)
-
大多数的运算符重载函数,一般有两种形式:
成员运算符函数
友元运算符函数 -
在成员运算符函数的形参表中:
若运算符是单目的,则参数表为空.
若运算符是双目的,则参数表中有一个操作数. -
如果在类X中采用成员函数重载双目运算符
aa @ bb; // 隐式调用
aa.operator @(bb); // 显式调用
采用成员函数重载单目运算符时,
@aa; // 隐式调用
aa.operator@( ); // 显式调用
虚函数
-
虚函数提供了一种更为灵活的多态性机制。虚函数允许函数调用与函数体之间的联系在运行时才建立,也就是在运行时才决定如何动作,即所谓的动态联编。
-
在一个派生类中重新定义基类的虚函数是函数重载的另一种形式,但它不同于一般的函数重载。
- 普通的函数重载时,其函数的参数或参数类型必须有所不同,函数的返回类型也可以不同。
- 当重载一个虚函数时,也就是说在派生类中重新定义虚函数时,要求函数名、返回类型、参数个数、参数的类型和顺序与基类中的虚函数原型完全相同。
- 如果仅仅返回类型不同,其余均相同,系统会给出错误信息;
- 若仅仅函数名相同,而参数的个数、类型或顺序不同,系统将它作为普通的函数重载,这时将丢失虚函数的特性。
- 在基类中,用virtual可以将其public或protected部分的成员函数声明为虚函数。
- 在派生类对基类中声明的虚函数进行重新定义时,virtual可写可不写。
- 虚函数被重新定义时,其函数的原型与基类中的函数原型必须完全相同。
- 虚函数必须是其所在类的成员函数,而不能是友元函数,也不能是静态成员函数。
- 构造函数不能是虚函数,但是析构函数可以是虚函数
纯虚函数
- 纯虚函数是一个在基类中说明的虚函数,它在该基类中没有定义,但要求在它的派生类中必须定义自己的版本,或重新说明为纯虚函数。
- 纯虚函数的定义形式如下:
virtual 函数类型 函数名(参数表)=0;
抽象类
如果一个类至少有一个纯虚函数,那么就称该类为抽象类。
- 抽象类只能作为其他类的基类来使用,不能建立抽象类对象,其纯虚函数的实现由派生类给出。
- 抽象类不能用作参数类型、函数返回类型或显式转换的类型。
- 如果在抽象类的派生类中没有重新说明纯虚函数,而派生类只是继承基类的纯虚函数,则这个派生类仍然是个抽象类。