Cpp速记

本文最后更新于:4 个月前

Cpp速记

第一章 面向对象和面向过程

面向过程

核心思想:功能分解
方法:自顶向下 逐层分解
设计范型:程序=算法+数据结构

面向对象

以类的形式将 数据及对数据的相应操作以 类 的形式封装 作为一个整体
以类的对象 作为程序的基本单位
通过向对象发送 消息 启动相关操作

类的特征:(组成)
静态特征 数据成员
动态特性 成员函数

类与对象 抽象与具体 类型与变量

面向对象 基本概念

特征

以类与对象作为核心概念 围绕类的定义及其使用的中心展开

  • 封装(封装机制~访问属性
  • 继承(提高代码重用性 组织、构造、重用类的重要手段
  • 多态(一种行为有多种实现方式 意义在于用一个接口实现不同操作

对类进行实例化的对象才有意义
采用 接口 间接操作数据成员

C++面向对象特征的体现

  • 支持封装性
  • 支持继承性(单继承和多继承)
  • 支持多态性(静态联编和动态联编)

C++为C的超集

Simula 67为面向对象语言 鼻祖

第二章 C++的改进与扩展

函数重载

函数重载(只关注形参 相同函数名 返回值类型无关联

形参默认值(定义首部和原型声明只能给一处,构造函数只能在类定义内部给出)

默认参数值(从右到左;实际参数(从左到右

输入输出控制流——I/O流
流:一个对象到另一个对象的流动
cin>>输入时提取符后面只能跟变量 空格会分割数据
cout<<表达式可以

注意:

cout<<fun1(a,b)<<fun2(a,c)<<endl; //这里函数执行顺序是从右往左的

cout跟printf是不同的,cout输出float或double,是会将小数点后非有效数字的0去掉的,而printf里面以%f输出规定是以6位小数输出,不管是不是有效数字 25

bool类型 常量true false(1 0
命名空间
定义方式
使用方式有三种 P14
其他
string类型的使用
域解析符::(不能重载

引用

定义方式

用& 不是取地址 而是声明引用

必须初始化 只能初始化一次

*注意:

不能创建引用的引用~&&a

不能创建指针的引用~&*p

不能创建引用的数组(无法创建由引用组成的集合,但可以创建数组的引用)

不能创建void类型引用

int& a[3]; // 错误
int&* p;   // 错误
int& &r;   // 错误

用途:
作函数的形参 (引用参数扩大了引用变量的作用域,方便改变实参变量的值)
作函数返回值

传值方式:

传值 传地址 引用传值 常引用传值

值形式参数 指针形式参数 引用形式参数 常引用参数的区分

常引用形式参数(const typename &a 常引用(引用变量a不能改变))的实际参数只能是变量,效率更高,无需分配额外空间,在函数中不能修改;

值形式参数可是变量、常量、表达式

引用作为函数返回值注意:

引用返回函数可以作为左值调用(放在等号左边

return后面只能是变量,不能是常量或常量表达式或常引用(只有变量可以作为左值

return后面变量的内存空间本次函数调用结束之后应当仍然存在(不能是局部变量)

引用返回的一般是函数中的一个引用形式参数

动态内存空间处理函数:new和delete

C和C++申请动态数组的比较(一维数组和二维数组)

C++中强制类型转换的两种方式 (type) express 和 type (express)
delete+数组名(而不加[])会只释放第一个元素的内存空间

tip

申请的空间 按逆序释放可预防错误
记得访问地址符*和自增自减的优先级
+± -

异常处理

目的:

对可以预测的错误(与期望结果不同)进行测试和处理

好处:将异常交给上级处理可以减轻底层函数负担(底层函数的具体实现没问题,让上级函数处理结果异常即可)

一定程度上保证了程序的健壮性

相关语句
throw

try-catch :
两者的语句块必须一起出现在可能出现异常的上级函数,之间不能有其他语句。
无异常便跳过catch部分,throw出异常便会中断语句块的余下部分。

第三章 类与对象

类是对某一类对象的抽象,对象是某一种类的实例

利用类可以实现对类的抽象、数据和操作的封装以及信息的隐藏

面向对象程序设计的首要任务是 类的设计,其次是通过对象来使用类

类的特征:(组成)
静态特征 数据成员
动态特性 成员函数

类的定义格式(和结构体相似

tips:

类里面定义的变量都是局部变量

注意分号别少

访问控制修饰符(省略了就默认是 private)

class
{
    public:
    	int a,d;
    protected:
    	double b;
    	string f;
    private:
    	float c;
    //成员函数类似定义格式
    public:
    	void SetA(int);
    	int GetA();
};

定义类的对象

类名 对象名1,[对象2,……,对象n]

定义类对象的几种方法:

(1) 先声明类类型,然后再定义对象

class Student{

};

Student stu1,stu2;

(2) 在声明类类型的同时定义对象

class Student{

}stu1,stu2;

(3) 定义匿名类,不出现类名,直接定义对象

class{

}stu1,stu2;

访问数据成员

对象名.成员

在类定义内部,成员之间可直接访问

在类的外部,只有public属性的成员,可以通过该格式直接访问(比如main函数)

成员函数的两种实现:

一般将成员函数定义为公有成员

可以在类外实现 和 类内实现

类内实现自动识别为 内联函数 ;如需类外实现内联函数,则在类定义中的相应函数首部 增加关键字 inline

内联函数减少函数调用的开发,一般最适用于那些非常短的简单函数,且不会显著增加可执行模块的大小

*访问属性

关键字:public,private(只能被该类成员函数访问),protected(只允许该类及其派生类成员函数访问)

(缺省时默认时私有private)

区分三种属性的作用:

  • 简单来说,派生类能访问基类的public, protected成员,继承过来权限不变,派生类对象只能访问基类public成员
  • 简单来说派生类可以访问基类的public, protected成员,继承过来之后变成自己私有的。 派生类的对象啥都不能访问。
  • 简单来说: 派生类可以访问基类的public, protected,继承过来都变成了protected,派生类对象啥都不能访问

*this指针

每一个成员,每个成员函数都有一个特殊的隐含指针,即this指针,用以存放当前对象的地址

对象调用成员函数——>对象内存中地址传递给this指针,初始化改指针常量——>调用用成员函数,通过this指针调用实例对象值——>返回值

内存地址开始的

构造函数和析构函数

这两种特殊函数,由系统自动调用

构造函数:

  • 函数名与类名相同,以类名为函数名则一定为类的构造函数
  • 没有返回值类型(给了会报错)、
  • 一定要是public属性(否则会报错)
  • 可重载的,要避免出现二义性
  • 没有定义系统会自动生成系统默认无参构造函数,自定义了任意一种构造,则系统不会再生成

tips:系统默认无参构造函数只会创建对象,分配空间,不初始化数据成员

构造函数的默认参数

再定义类的构造函数时,可以指定形参默认值,但必须在 类定义的内部 给出

即类内只给出原型,而在类外实现时,默认形参也应该放在原型中

带默认参数的构造函数比较安全

初始化列表

初始化列表 初始化顺序只和成员变量声明顺序相关

某些数据成员初始化的唯一方法:

  • 需要初始化的数据成员是对象的情况(这里包含了继承情况下,通过显示调用父类的构造函数对父类数据成员进行初始化);
  • 需要初始化const修饰的类成员或初始化引用成员数据;
  • 子类只能用列表初始化父类的私有成员;
class Test
{
	private:
		int a;
};

class Test2:public Test
{	
	public:
		Test2:Tset(2){
			//Test(2);//不能在内部调用,报错
		};

};

引用和常量的初始化 只能用 初始化列表

复制构造函数

不自定义会自动生成

类名(const 类名 对象名);

系统调用复制构造函数的三种情况:

  1. 明确表示由一个一定义的对象初始化一个新对象
  2. 函数形参为一个对象(如果时引用或者指针对象的形参,则不会调用
  3. 对象作为返回值

析构函数

~类名( );

注意:

  • 不能重载
  • 没有形参
  • 每个类只能有一个

调用情况:

  • 对象生命期结束时系统自动自动调用
  • delete释放用new申请的内存,也会自动调用

析构函数和delete

*调用规则:

析构函数的调用顺序永远和构造函数的相反

类定义中有对象成员时,构造函数的调用是 由内到外的(先构造对象成员,在构造整个对象)

(总结一下各种特殊函数的调用顺序)

深复制和浅复制

浅复制容易产生指针悬挂的问题

在复制构造函数换和对象赋值运算中会存在该问题

静态成员

必须在类外进行

类型 类名::静态数据成员名=初始值	//只能在类外进行初始化
e.g:
int Test::Count=0;

访问格式

Test::Count
或者
Test t
t.Count

静态成员没有this指针,无法调用非静态函数,只能调用静态成员数据

static const 可以让数据只保存一份副本 减少空间开销

静态常数据成员

static const type name

初始化不能在初始化列表

在类定义结束后,单独初始化

也可以在类定义中初始化

const typename Test::name=value;

常对象

定义常对象必须初始化

this指针是一个指针常量,成员函数中访问对象中的数据成员会隐式使用this指

常对象只能调用常成员和常成员函数

常数据成员和常成员函数

const typename;	//只能在构造函数初始化列表进行初始化
typename function() const;	//const声明让this指针可以指向常对象可以作为函数重载的标志

*tips:

  • 常成员函数不能调用未经关键字const修饰的成员函数,但是普通成员函数是可以调用常成员函数的
  • 当类中的一个函数有普通函数版本和const修饰的重载版本,常对象会直接调用const版本;普通函数会优先调用普通成员函数,若没有普通版本,则可以调用const版本

友元

三种形式:

  • 友元函数——独立函数友元
  • 友元成员——某一个类中的成员函数声明友元
  • 友元类——某一个类声明友元

friend关键字

tips:

  • 友元函数的实现写在类外的时候,不用加关键字
  • 在类内给出实现时,默认内联函数
  • 声明友元成员和友元类的时候,记得加入前向声明

第四章 继承

继承机制:

对一个已存在的类进行属性和功能拓展,得到一个新的类

注意继承带来的问题:

访问属性变化,同名冲突等

C++支持多继承,旧的类叫做基类,新类叫做派生类

派生类

定义:

class 派生类名::继承方式 基类名[,基类名1,...,基类名2]
{

}

继承方式:public,private,proected

基类的构造函数和析构函数不能被继承

注意不同继承方式导致的基类成员在访问控制权限的变化

派生类只负责直接基类的构造函数调用,若直接基类构造函数无需参数,可以不再初始化列表中列出

使用virtual只有一份拷贝 虚继承体系中的每个类的对象访问的是同一份数据

用虚基类可以避免同名冲突问题

虚基类构造函数只在最后一层调用才会发挥作用

创建一个对象时,构造函数的调用顺序:

  • 所有虚基类构造函数(按定义顺序)
  • 所有直接基类的构造函数(按定义顺序
  • 所有对象成员的构造函数(按定义顺序
  • 派生类自己的构造函数
A a = A();	//这样调用一个构造函数生成一个临时变量进行赋值 接着马上析构

赋值兼容规则

相当于java中的上转型

第五章 多态

多态性是指一种行为多种不同实现

多态的实现:

  • 静态联编——编译时多态性
  • 动态联编——运行时多态性

实现技术:

  • 静态——函数重载和运算符重载
  • 动态——继承、虚函数、基类的指针或引用等(虚基类不包括

运算符重载

重载方式:

  • 成员函数重载

    e.g:
    	Complex operator + (形参);
  • 友元函数重载

    e.g:
    	friend Complex operator + (形参,)

注意:

  • 除了赋值运算符及符合赋值运算符的重载,其余运算符重载都能被派生类继承

  • 不能重载的运算符:

    .	::	?:	sizeof	.*
  • 运算符重载有隐式和显式两种调用

几种需要注意的运算符重载

  • =:只能重载为成员函数,不能被继承,注意深复制和浅复制问题

    类名& operator = (const 类名&);
    e.g:
    	CMessage& Cmessage::operator = (const Cmessage &s);
  • [] : 带一个右操作数的运算符,只能重载为成员函数

    • 一定以某种类型的引用返回,从而使函数返回值可以作为左值
    • 形式参数表中有一个形参数
  • 提取运算符>> 和插入运算符<<:需要用友元函数进行重载,必须返回流类的引用

    类内声明:
    friend istream & operator >>(istream & in,用户自定义类型 & obj);
    friend ostream & operator >>(ostream & out,const 用户自定义类型 & &obj);
  • 后缀 和–的重载函数,形参列表中要增加一个int,但不必写形参名(a);前缀++(++a)不用+。

动态多态性实现

虚函数

定义:

virtual 返回类型 成员函数名(形参);

作用:

虚函数可以通过基类指针或引用访问基类和派生类中被声明为虚函数的同名函数

条件:

  • 存在继承关系 且必须是 公有继承
  • 同名虚函数在基类和派生类中的函数原型完全一致(返回值类型 函数名 形参参数表)
  • 必须定义基类指针的引用和指针

tips:

  • 静态成员函数、内联成员函数、构造函数不能声明为虚函数

  • 析构函数可以是虚函数,且往往声明为虚函数,即虚析构函数

  • 虚析构函数能保证申请的动态空间能被正常释放

抽象类

定义:

类中至少包含了一种纯虚函数的类,为所有派生类提供了统一的接口

纯虚函数定义:

virtual 返回值类型 函数名( ) = 0;	//"=0"声明这是一个纯虚函数

tips:

  • 抽象类不能生成对象,抽象类的派生类都应该重新定义该函数
  • 可以定义抽象类的指针或引用
  • 抽象类的基类只能是抽象类
  • 抽象类里还可以定义普通成员函数或者虚函数

用到关键字virtual的情况:

  • 定义虚函数,虚基类
  • 友元函数、构造函数 静态函数 不能用virtual修饰
  • 普通成员函数 析构函数 常成员函数可以用virtual修饰

第六章 模板

函数模板

template<typename 形参1,typename2 形参2,...typename3 形参n>
返回值类型 函数名(形参表)
{

}

类模板

template<typename1 形参1,typename2 形参2,...typename3 形参n>
class 类名
{
	
};

实例化才可以进行使用

函数模板也可以进行重载


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!