admin 管理员组

文章数量: 1184232


2024年3月21日发(作者:power梗出自哪里)

第一章 面向对象

第一节 类与对象

一、类

1、类的概念

类是对数据的一种抽象,所谓抽象就是将一些事物中不需要的数据剔除,而留下程序需要的。

类的声明

声明一个类的语法:

class 类名

{

private:

//私有的成员

public:

//公有的成员

};

2、类的成员

➢ 在类中可以声明任意类型的变量,即成员变量,表示这个类的属性。比如说学生可以有

一个整形变量表示id,字符数组表示姓名,浮点型变量表示成绩。

➢ 在类中可以声明函数,即成员函数,表示这个类的行为。比如说学生可以有一个print

函数打印自己的成绩。

3、类的定义

➢ 主要是对类中的成员函数进行定义

➢ 定义类成员函数的语法:

返回值类型 类名 :: 函数名(参数列表)

{

函数体

}

4、定义类成员函数的注意事项

当类成员函数定义在类的外部时,一定要在函数名前加上“类名::”,以引来表示该函数是类

的成员函数。

在类的成员函数中可以自由的访问该类的其他成员属性和成员函数。

类成员函数的定义一般写在与头文件对应的.cpp文件中。

二、对象

1、对象的概念

➢ 从广义上讲,要在内存上一段有意义的区域就称之为对象。

➢ 在c++中,对象一般是指类在内存中装载的实例,具有相关的成员变量和成员函数。类

是抽象的概念,而对象是通过类实现的具体实例。

➢ 比如说,学生是类,学生小明是对象

➢ 对象调用公有成员:可以通过运算符“:”或者 “->”访问对象里的公有(public)成员

➢ this指针:

 当通过对象调用成员函数传递参数时,会额外将本身的地址做为参数传递进入函数。

比如说我们实际调用成员函数如下:

 uce();

 实际上编译器认为的代码是:

 uce(&tom);

2、构造函数和析构函数

➢ 由于对象一定会在内存中占用一段空间,所以一定会有其生命周期。也就是说对象一定

有申请内存空间和释放内存空间的步骤。

➢ 构造函数是当对象申请内存空间之后自动调用的函数。

➢ 析构函数是当对象的空间即将被销毁前自动调用的函数

2..1、构造函数

2.1.1 构造函数声明

➢ 构造函数的声明需要在类中声明。

➢ 构造函数没有返回值。

➢ 构造函数的函数名必须和类名一致。

2.1.2、构造函数的定义

➢ 构造函数可以直接定义在类内部,也可以直接定义在类的内部。

➢ 定义在类内部的方式:

 类名(参数){ //函数体}

➢ 定义在类外部的方式:

 类名::类名(参数列表){ //函数体}

➢ 构造函数列表初始化(const成员只能被初始化,不能被赋值)

 可以用列表初始化的方式对类成员直接赋值,这样做会提高程序运行效率。

类名::构造函数(参数1,参数2,……)

:类成员(参数1),类成员(参数2),……

{//其它属性初始化}

注意:列表初始化对方式只支持将参数通过赋值运算赋值给类成员。

注意:列表初始化成员的顺序必须和类成员声明的顺序一致。(只要成员变量的初

始化不依赖其他成员变量,即使顺序不同也能正确的初始化。)

2.1.3、构造函数的特点

➢ 用于初始化对象的成员属性

➢ 构造函数的函数名必须与类名一致。

➢ 构造函数没有返回值。

➢ 同一个类可以有多个参数列表不同的构造函数。

➢ 当且仅当一个类没有声明构造函数里,编译器会自动生成一个无参无内容的构造函数。

2.1.4、构造函数隐匿调用

当构造函数只有一个参数时,就可能出现构造函数隐匿调用现象。例如:Number i=55;这样

的现象。

55是一个整数,i是一个Number类型,这却可以让整数初始化自己定义到类型。因为在这

个过程中出现了构造函数隐匿调用的情况。

注意:在构造函数声明前加上explicit关键字可以关闭构造函数隐式调用的功能。

2.2、析构函数

2.2.1析构函数的声明

➢ 析构函数的函数名以~+类名

➢ 析构函数没有返回值

➢ 析构函数没有参数列表

2.2.2析构函数的定义

析构函数即可以在类的内部定义也可以在类的外部定义

类内部定义:

~类名(参数列表){ //函数体}

类外部定义:

类名::~类名(参数列表){ //函数体}

三、new和delete

new和delete是C++中的两个关键字,主要用于在向堆申请或者释放空间。

和C语言中申请堆内存不同的是,new和delete在申请/释放空间的时候还会调用构造和析

构函数。

1、new的使用方法

 使用new创建对象:

 类名 * 变量名 = new 构造函数(参数列表);

 使用new创建对象数组:

 类名 * 变量名 = new 类名[数组的大小]; //此时会调用多次构造函数

2、delete的使用方法

 使用delete销毁对象:

 delete指向对象的指针; //此时会调用析构函数

 使用delete销毁对象数组:

 delete []对象数组名; //此时会调用多次析构函数

 注意delete 和delete[]的选择。

四、string类型

1、string类型介绍

 标准库类型string表示可变长的字符序列,使用string类型必须产生包含string.头文

件。

 建议在C++中使用String表示字符串,而不是使用C风格的字符串。

2、string类型的操作

 使用string类型必须首先包含string头文件。作为标准库的一部分,string定义在命名

空间std中。

 #include

 using namespace std;

 如何初始化类的对象是由类本身决定的,一个类可以定义很多种初始化对象的方式,只

不过这些方式之间必须有所区别

使用方法

string s1;

string s2(s1);

string s3=s2;

使用结果

空的字符串

初始化s2为s1的副本

初始化s3为s2的副本

();

();

s[n];

s1+s2;

s1=s2

s1==s2

s为空返回true,,否则返回false

返回s中的字符个数

返回s中第n个字符的引用,从0开始

返回s1和s2连接后的结果

用s2的副本代替s1中原来的字符

判断字符串是否相等

使用cin输入单

个字符串:

cin >> s;

使用cin输入多

个字符串,以空

白间隔:cin >> s1 >> s2;

使用getline读取一整行: getline(cin,line);

第二节 封装

一、封装的概念

 面向对象的三大特性有封装,继承,多态。

 封装主要是指信息隐藏,隐藏对象的实现细节,不让外部直接访问到。

 比如说,学生类中的成员属性姓名,它可以是字符数组,也可以是string类型。但是当

我们使用对象的时候并不需要知道姓名这个属性到底在内存中是以字符数组还是string

类型存在。

 访问控制

 在C++语言上,我们使用访问说明符加强类的封装性:

➢ pubic:表示该成员在成员函数中直接访问,也能通过对象访问。

➢ private:表示该成员能在成员函数中直接访问,但不能通过对象访问。

 存取器

 因为封装的缘故,类里面的成员变量一般会被定义为private,防止外部程序随意更

改。

 为了允许修改或读取对象的私有成员,就要提供公开的存取器函数。

二、封装的目的

 实现信息的隐藏。

 将使用者不需要知道的,或者不应该知道的数据处理流程隐藏起来,只留下操作接口。

 保护对象数据不被任意的使用与更改,欲修改数据都要通过特定接口。

1、静态成员的概念

在c++中,静态成员是属于整个类的属性或行为的而不是属于某个对象的,所有对象共享这

些属性和行为。

2、静态成员的声明(在声明前加static关键字)

静态成员变量的声明:

static 变量类型 变量名;

静态成员函数的声明

static 返回类型 函数名(参数列表);

3、静态成员的定义

静态成员变量的定义:

变量类型 类名::变量名 =初始值;

静态成员函数的定义:

返回值类型 类名::函数名(参数列表){}

4、单例模式

单例模式是一种常用的软件设计模式 。在它的核心结构中只包含一个被称为单例的特殊类。

通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实

例个数的控制并节约系统资源。

(1、饿汉模式:初始化时直接创建对象,不会有线程安全问题,

2、懒汉模式:初始化时不创建对象,在第一次调用时创建对象,存在线程安全问题)

第三节 引用

一、引用的概念

引用(reference)为某个对象起了另外一个名字。

引用并非对象,对引用进行的所有操作都是在与之绑定的对象上进行。

二、引用的注意事项

➢ 通过将声明符&来定义引用类型,而且引用必须绑定到特定的对象上,并且一经绑定无

法解除。

 引用类型 & 引用名 =特定的对象;

 如 :int a=0;

 int & r=a;

➢ 引用只能绑定到相同类型的对象上,如下是错误的:

 int & r=314; //3.1是浮点类且是常量,所以不能绑定到int引用上

➢ 使用引用的目的

 可以在传递函数时,避免调用拷贝构造函数,提供程序执行效率。

三、拷贝构造函数

➢ 拷贝构造函数是一种特殊的构造函数,其唯一的形参必须是构造对象的引用。

➢ 编译器会自动生成拷贝构造函数,自动生成的拷贝构造函数会将参数中的所有非静态成

员拷贝给当前对象。

➢ 以下三种情况会调用拷贝构造函数:

 对象作为函数参数,以值传递的方式传入函数体。

 对象作为函数返回值,以值传递的方式从函数返回。

 对象用于给另一个对象进行初始化。

四、关键字const

1、const引用

➢ 由const关键字修改的引用,称之为对常量的引用,简称为常量引用。

➢ 与普通引用不同的是,对常量的引用不能被用作修改它所绑定的的对象;

 const int ci=1024;

 cinst int & r1=ci;

➢ 常量引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是一个常量未做

限定,即const引用即可绑定常量对象上也能绑定到非常量对象上。

➢ 尽可能在参数传递时使用const引用。

2、const成员函数

➢ 当成员函数不会更改对象的任何成员变量时,可以将成员函数声明为const:

 class 类名{

 public:

 返回类型 函数名(参数列表)const;

 }

 返回类型 类名::函数名(参数列表)const{函数体}

➢ const修饰的对象和普通对象不同,它只能调用const修饰的成员函数,而普通对象可

以调用任何成员函数。

➢ 将const修饰成员函数的目的,是为了确认该成员函数可作用于const对象身上。

3、const_cast

➢ 对于将常量对象转换成非常量对象的行为,一般称其为“去掉const性质”。一旦去掉了

某个对象的const性质,编译器就不再阻止我们对该对象进行写操作了。

➢ 如果对象本身不是一个常量,使用强制类型转换获得写权限是合法的行为。然而如果对

象是一个常量,再使用const_cast执行写操作就会生产未定义的后果。

➢ 使用方法:

 const char *pc;

 char *p =const_cast(pc);

 char &r =const_cast(*pc);

第四节 重载

一、重载的概念

 编程中重载是指函数名相同,函数的参数列表不同(包括参数个数和参数类型),至于

返回类型可同可不同。

 重载是可使用相同函数、运算符等处理不同类型数据或接受不同个数的参数的一种方法。

二、运算符重载的概念

 运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数

据类型。

 重载的运算是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运

算符号共同组成:

 返回类型 operator运算符(参数列表);

三、运符符重载为函数

➢ 运行符重载为函数的参数数量应与该运算符的运算对象数量一样多。一元运算符有一个

参数,二元有两个参数。参数的类型应该根据运算符要操作的对象类型决定。

➢ 比如说,我们希望重载运算符支持CompleNumber的加法,则运算符会操作两个

CompleNumber对象:

 CompleNumber c1 c2;

 CompleNumber c3=c1+c2;

➢ 以下运算符是不能重载的:

 条件运算符 (?:)

 作用域运算符 (::)

 成员指针运行符 (.*)

四、运算符重载为成员函数

如果要将运算符重载为成员函数,则运算符的第一个操作的元素为当前对象(也就是this指

针),如果有第二个操作的元素则由参数指定,因此,运算符重载为成员函数的参数数量比

运算符重载为函数的参数数量少一个。

1、默认参数的概念

函数的默认参数值,即在定义参数的时候同时给它一个默认值,在调用函数传参的时候,可

以省略含有默认值的参数。

例如:

void func(int i=0;int j=1);

注意事项:

默认参数的值是严格按照从右至左的顺序指定。

默认参数的值只能在声明或定义中一处指定,不能同时指定

默认参数和函数重载会出现二义性问题,如:

void func(); 和void func(int i=0);

第五节 友元

一、友元的概述

➢ 友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被为友元类。

➢ 友元提供了不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。

通过友元,一个不同函数或另一个类中的成员函数可以访问类中的非公有成员。

二、友元类

➢ 友元类是能够通过成员函数访问其它类中的非公有成员的类。从语法上看,它与普通类

一样,只是友元类需要在访问私有成员的类中额外声明,并丰声明前加上friend关键

字。

➢ 友元类的声明:

 friend class 类名:

第六节 内联函数

一、内联函数的介绍

➢ 内联函数是指用inline关键字修饰的成员函数或非成员函数。

➢ 内联函数具有函数的结构,而在编译后,却不具有函数的性质。编译时,类似宏替换,

使用函数体替换调用处的函数名。

二、内联函数的注意事项

内联函数中不允许使用循环语句、switch语句、递归调用。

内联函数只适用于1~5行的小函数。

在类结构内部定义的函数默认为内联函数。

内联函数的声明定义写在头文件中。

inline关键字只是向编译器提出内联的请求,编译器有可能忽略这个请求。

第七节 继承

一、继承

1、继承的概念

➢ 继承是类与类之间的一种关系。如果类A继承于类B,则把类B称为基类(父类),类

A称为派生类(子类)。

➢ 继承需要符合is-a的关系,基类更通用更抽象,派生类更特殊更具体。

➢ 比如说动物是一个类,食肉动物也是一个类。而动物有的特性食肉动物都有,也就是说

食肉动物是动物(is-a),即食肉动物继承于动物。同理,当狮子看作一个类时,它也应

当继承于食肉动物 。

2、继承的目的

➢ 提高代码的重用性。因为派生类会拥有基类的所有特性,所以当写派生的时候就没有必

要把基类相同基类相同功能的代码再写一遍。

➢ 提高代码的可拓展性。派生类可以在基类的基础上添加新的代码,而且一个基类可以出

现多个派生类

3、简单的继承

公有继承的子类声明:

二、继承相关

1、对象的构造和析构过程

➢ 任何对象在创建后都会调用构造函数,在销毁之间才会调用析构函数。

➢ 因为派生类对象除了本身成员之外还拥有基类的成员,所以派生类对象在创建时会调用

父类的构造函数,销毁时调用父类的析构函数。

2、派生类的构造函数

➢ 在定义派生类的构造函数是需要知道父类的构造函数,如果不指定则会调用父类的无参

构造函数。

➢ 派生类构造函数定义:

3、访问控制符

➢ private:只有能在当前类成员函数中能够访问。

➢ protected:只有在当前类成员函数和子类成员函数中能够访问。

➢ public:即能在当前类成员函数,子类成员函数中访问,也能通过当前类对象,子类对象

访问。

4、受保护继承和私有继承

➢ 在c++中最常见的是公有继承,除了公有继承外,还有受保护继承和私有继承。

➢ 在受保护继承中,派生类从基类继承下来的私有成员会隐藏,所有非私有成员才会变成

保护成员。

➢ 在私有继承中,派生类从基类继承下来的私有成员会隐藏,所有非私有成员都会变成私

有成员。

三、虚拟继承

➢ 虚拟继承是多重继承中特有的概念,是为了解决多重继承出现的菱形继承。

➢ 比如,熊猫继承自类熊、浣熊,而熊、浣熊都继承自动物,则此时熊猫中会出现两次动

物中的成员。

➢ 为了节省内存,可以将熊、浣熊对动物的继承定义为虚拟继承,到此在熊和浣熊出现的

继承体系中只会出现一份动物的实例。

1、虚函数的概念

➢ 虚函数是指在类成员函数声明前加上virtual关键字的函数。

➢ 当基类的成员函数无法满足子类要求的时候,我们可以将该成员函数声明为虚函数以供

子类改写,虚函数的声明方式如下:

2、虚函数列表

➢ 当一个类中出现了虚函数时,编译器会为这个类的对象多分配4个字节的空间用于存

放虚函数列表。

➢ 在虚函数列表中存放了所有虚函数的函数指针。

➢ 当对象调用虚函数时,会优先从虚函数列表中寻找匹配的函数指针进行调用。

3、函数重写

➢ 派生类可以对基类的虚函数进行重新声明定义,这种行为称之为函数重写。

➢ 函数重写会将派生类对象继承自基类的虚函数列表部分进行重写。

四、纯虚函数和抽象类

1、纯虚函数的概念

纯虚函数是只需要声明,不需要定义的虚函数。声明方法如下 :

2、抽象类的概念

➢ 有纯虚函数的类被称为抽象类。

➢ 抽象类无法通过构造函数直接生成对象,只能够派生类继承。

➢ 当抽象类被继承时,该类的所有纯虚函数必须在子类中重写,否则子类也将称为一个抽

象类。

3、多态的概念

 在面向对象语言中,接口的多种不同实现方式即为多态。

 多态能允许将父对象设置成一个或更多个它的子对象的技术,赋值之后父对象就可以根

据当前赋值给它的子对象的特性进行动作。

 可以简单的理解为:将基类对象的指针或引用绑定到派生类对象上,此时基类的指针或

引用就可以拥有派生类的特性。

4、通过函数重写实现多态

实现多态的步骤:

 第一步,派生类重写基类的虚函数。

 第二步,基类的指针或引用绑定到派生类的对象上。

 第三步,通过基类的指针或引用调用所绑定派生类重写过的函数。

知识点总结

1、编程思想

C++语法+编程思想 ->面向对象(OO:object oriented)

面向对象 <-> 面向过程

抽象 <-> 具体

面向对象:优化、维护、升级、、并行开发、臭味低、耦合低

c++:兼容C,升级版,基于面向对象设计出的开发语言。

面向对象:封装、继承、抽象、多态

2、C++中标准库头文件:

am ->标准IO流头文件

2.如果使用C标准库,比如stdio.h,添加头文件时,可以直接

#include

#include ->最好这样写,.h去掉,前面加C

3、常见运算符

cout,endl,”” -> 对象

<< >> -> 流运算符

cout => console out 输出控制台,使用流运算符将数据往输出控制台给进去,则输出控制

台会将收到的数据,输出出去。

endl => end line : ‘n’+fflush;

fflush => 给到哪,哪就清缓存

cin => console in 输入控制台

流运算符的右值类型:基本数据类型,指针都可以。

4、关于类

类的非静态成员函数,非静态成员函数的调用,必须通过该类具体对象+访问运算符进行调

用,无法直接全局调用。

类的非静态成员函数,为什么必须通过该类的对象来调用呢?因为此函数,语法上决定了一

个“隐藏的”参数=>this指针。

指针类型:该类 类型的 指针常量 => 类名* const this;

2.传参怎么传:调用对象的地址。

5、修改符

访问限制符:public private protected

公开,私有,受保护,对类的成员进行修饰,成员的访问权限发生变化

公开成员:可以直接通过对象全局访问,也可以在类的成员函数内部,通过this指针访问。

私有、受保护:不可以直接通过对象全局访问,但是可以在类的成员函数内部,通过this指

针访问。

私有成员访问:公开接口进行访问,常见访问get/set

6、引用

引用:变量的别名,当引用变量a,绑定实际变量b之后,对a所有的操作,即对b操作。

语法:定义变量时,使用&表示引用变量。

注意:

a) 初始化的时候绑定,且只能绑定一次,且必须绑定

b) 必须绑定具体变量,不能绑定常量

c) 绑定对象的类型,与绑定变量本身的类型,必须一致。隐式转换也不算

7、类的特殊函数

构造函数:constructor ->初始化

初始化,必然是生成的时候,顺便第一次初始化,所谓生成指申请内存定义申请内存。

构造函数:无返回值,函数名=类名,参数根据需求

当变量被定义的时候,自动被调用,且只能被调用一次。

构造函数,可以定义多个,前提参数不能一样

具体调用,是在创建具体对象时,根据其初始化参数,自动匹配并调用的。

析构函数

:当对象的生命周期结束时,自动被调用

无返回 函数名为 ~类名 参数没有


本文标签: 函数 成员 对象