C++期末复习

掐指一算,还有十天考C++。
本博客基于此博客进行修改,更适合我自己使用,结合了老师的课件。

1、数据类型

sizeof关键字
作用:利用sizeof关键字可以统计数据类型所占内存大小

1.1、整型

作用:整型变量表示的是整数类型的数据

  • int - 占4个字节
  • unsigned int - 无符号整型,占4个字节

1.2、浮点型

作用:用于表示小数

浮点型变量分为两种:

  • 单精度float ➡占4个字节,提供6位有效数组
  • 双精度double ➡占8个字节,提供15位有效数字

1.3、数值型常量

1.3.1数值常量

一个整型常量可以用3种不同的方式表示:

  • 十进制整数。如1357,-432,0等
  • 八进制整数。在常数的开头加一个数字0,就表示这是以八进制数形式表示的常数。
  • 十六进制整数。在常数的开头加一个数字0和一个英文字母X(或x),就表示这是以十六进制数形式表示的常数

1.3.2浮点数的表示方法

一个浮点数可以用两种不同的方式表示:

  • 十进制小数形式。如21.456,-7.98等。
  • 指数形式(即浮点形式)

1.4、字符型常量

作用:字符型变量用于显示单个字符

语法:char ch = ‘a’;

  • 注意1:在显示字符型变量时,用单引号将字符括起来,不要用双引号(双引号一般表示字符串)
  • 注意2:单引号内只能有一个字符,不可以是字符串(跟废话一样)

C和C++中字符型变量只占用1个字节。(一个字节是8位)

字符常量只能包括一个字符。
字符常量区分大小写字母,如′A′和′a′是两个不同的字符常量。
字符型变量并不是把字符本身放到内存中存储,而是将对应的ASCII编码放入到存储单元。

1.5、字符串型常量

作用:用于表示一串字符

两种风格

C风格字符串: char 变量名[] = “字符串值”
char str1[] = “hello world”;

注意:C风格的字符串要用双引号括起来

C++风格字符串: string 变量名 = “字符串值”
string str = “hello world”;

注意:C++风格字符串,需要加入头文件==#include==

字符串常量为双引号.

常考:字符串 “abc” 在内存中占几个字节?
答:占4个字节,而不是3个字节,编译系统会在字符串最后自动加一个′\0′作为字符串结束标志。但′\0′并不是字符串的一部分,它只作为字符串的结束标志

常考: 字符串常量″abc\n″包含几个字符?
答:4个字符,‘\n’也是一个字符。

1.7、布尔类型bool

作用:布尔数据类型代表真或假的值

bool类型只有两个值:

  • true — 真(本质是1)
  • false — 假(本质是0)
    bool类型占1个字节大小

其实在高版本的C语言中也有对应的类型,_Bool类型。

1.8、数据的输入输出

关键字:cin、cout

语法: cin >> 变量1>>变量2>>…>>变量n、cout<<表达式1<<表达式2<<…<<表达式n

  • cout<<a,b,c; //错误,不能一次插入多项
  • cout<<a+b+c; //正确,这是一个表达式,作为一项
cin>>a>>b>>c>>d;

1
2
3
4

1.9、变量命名规则

C++规定标识符只能由字母、数字和下划线3种字符组成,且第一个字符必须为字母或下划线
不能是关键字
区分大小写
(基本所有语言都是这么要求的,记住首字母不能是数字,在一些情况下中文变量名也是允许的)

1.10、局部变量

在一个函数内部定义的变量是局部变量,它只在本函数范围内有效,也就是说只有在本函数内才能使用它们,在此函数以外是不能使用这些变量的
形参也是局部变量

1.11、全局变量

在函数之外定义的变量是外部变量,称为全局变量

2、运算符

2.1、算数运算符

基本上都是这些东西,在各个语言中。
运算符 术语 示例 结果

  • 正号 +3 3
  • 负号 -3 -3
  • 加 10 + 5 15
  • 减 10 - 5 5
  • 乘 10 * 5 50
    / 除 10 / 5 2
    % 取模(取余) 10 % 3 1
    ++ 前置递增 a=2; b=++a; a=3; b=3;
    ++ 后置递增 a=2; b=a++; a=3; b=2;
    – 前置递减 a=2; b=–a; a=1; b=1;
    – 后置递减 a=2; b=a–; a=1; b=2;
    注意:

两个整数相除结果依然是整数(这里不进行四舍五入,直接舍去小数点后面数字)
C++中两个小数可以相除
运算的两个数中有一个数为float型数据,则运算的结果是double型,因为C++在运算时对所有float型数据都按double型数据处理
只有整型变量可以进行取模运算,两个小数不可以取模
在除法运算中,除数不能为0
取模运算时,除数也不能为0

常考:
前置后置运算符单独使用没有什么区别
前置递增先对变量进行++,再计算表达式
后置递增先计算表达式,后对变量进行++

请详细看下方代码并理解

//递增
int main() {

	//后置递增
	int a = 10;
	a++; //等价于a = a + 1
	cout << a << endl; // 11

	//前置递增
	int b = 10;
	++b;
	cout << b << endl; // 11

	//区别
	//前置递增先对变量进行++,再计算表达式
	int a2 = 10;
	int b2 = ++a2 * 10;
	cout << b2 << endl; //110

	//后置递增先计算表达式,后对变量进行++
	int a3 = 10;
	int b3 = a3++ * 10;
	cout << b3 << endl; //100

	system("pause");

	return 0;
}

2.2、赋值运算符

作用:用于将表达式的值赋给变量

运算符 术语 示例 结果
= 赋值 a=2; b=3; a=2; b=3;
+= 加等于 a=0; a+=2; a=2;
-= 减等于 a=5; a-=3; a=2;
= 乘等于 a=2; a=2; a=4;
/= 除等于 a=4; a/=2; a=2;
%= 模等于 a=3; a%2; a=1;

2.3、比较运算符

作用:用于表达式的比较,并返回一个真值或假值

运算符 术语 示例 结果

==	相等于	4 == 3	0
!=	不等于	4 != 3	1
<	小于	4 < 3	0
>	大于	4 > 3	1
<=	小于等于	4 <= 3	0
>=	大于等于	4 >= 1	1

注意:C和C++ 语言的比较运算中, “真”用数字“1”来表示, “假”用数字“0”来表示。只是一种表示方式,用七八九十当真都可以。

2.4、逻辑运算符

作用:用于根据表达式的值返回真值或假值

运算符 术语 示例 结果
! 非 !a 如果a为假,则!a为真; 如果a为真,则!a为假。
&& 与 a && b 如果a和b都为真,则结果为真,否则为假。
|| 或 a || b 如果a和b有一个为真,则结果为真,二者都为假时,结果为假。
!非为三者中运算符最高的

3、流程结构

3.1、选择结构

3.1.1、if语句

if语句较为简单,常常搭配else使用,且可以嵌套使用

3.1.2、三目运算符

作用: 通过三目运算符实现简单的判断

语法:表达式1 ? 表达式2 :表达式3

如果表达式1的值为真,执行表达式2,并返回表达式2的结果;

如果表达式1的值为假,执行表达式3,并返回表达式3的结果。

非常基本的内容了。

3.1.3、switch语句

作用:执行多条件分支语句

语法:

switch(表达式)

{

	case 结果1:执行语句;break;

	case 结果2:执行语句;break;

	...

	default:执行语句;break;

}

switch语句中表达式类型只能是整型或者字符型
case里如果没有break,那么程序会一直向下执行,执行完case1再执行case2

3.2、循环结构

3.2.1、while

作用:满足循环条件,执行循环语句

语法:while(循环条件){ 循环语句 }

解释:只要循环条件的结果为真,就执行循环语句
就挺基础的。。。

3.2.2、do…while

作用: 满足循环条件,执行循环语句

语法: do{ 循环语句 } while(循环条件);

注意:与while的区别在于do…while会先执行一次循环语句,再判断循环条件

3.2.3、for

for循环中的表达式,要用分号进行分隔

int main() {

	for (int i = 0; i < 10; i++)
	{
		cout << i << endl;
	}
	
	system("pause");

	return 0;
}

3.3、跳转语句

3.3.1、break

作用: 用于跳出选择结构或者循环结构

3.3.2、continue

作用:在循环语句中,跳过本次循环中余下尚未执行的语句,继续执行下一次循环

注意:continue并没有使整个循环终止,而break会跳出循环

4、数组

数组:所谓数组,就是一个集合,存放相同类型的数据元素

数组中的每个数据元素都是相同的数据类型
数组是由连续的内存位置组成的
C语言中的字符串就是一种字符数组。

4.1、一维数组

一维数组定义的三种方式:

数据类型 数组名[ 数组长度 ];(常用,了解其余两种即可)
数据类型 数组名[ 数组长度 ] = { 值1,值2 ...};
数据类型 数组名[ ] = { 值1,值2 ...};
int score[10];
int score2[10] = { 100, 90,80,70,60,50,40,30,20,10 };
int score3[] = { 100,90,80,70,60,50,40,30,20,10 };
1
2
3

数组中下标是从0开始索引
在对全部数组元素赋初值时,可以不指定数组长度
直接打印数组名,可以查看数组所占内存的首地址
对数组名进行sizeof,可以获取整个数组占内存空间的大小

4.1.1、一维数组初始化

在定义数组时分别对数组元素赋予初值。例如
int a[10]={0,1,2,3,4,5,6,7,8,9};

可以只给一部分元素赋值。例如
int a[10]={0,1,2,3,4};

如果想使一个数组中全部元素值为1,可以写成
int a[10]={1,1,1,1,1,1,1,1,1,1};
int a[10]={1*10}; // 错误写法,不能给数组整体赋初值

在对全部数组元素赋初值时,可以不指定数组长度
int a[5]={1,2,3,4,5};
// 可以写成
int a[]={1,2,3,4,5};

4.2、二维数组

二维数组定义的四种方式:

数据类型 数组名[ 行数 ][ 列数 ];
数据类型 数组名[ 行数 ][ 列数 ] = { {数据1,数据2 } ,{数据3,数据4 } };
数据类型 数组名[ 行数 ][ 列数 ] = { 数据1,数据2,数据3,数据4};
数据类型 数组名[ ][ 列数 ] = { 数据1,数据2,数据3,数据4};
int arr[2][3];

int arr2[2][3] =
{
    {1,2,3},
    {4,5,6}
};

int arr3[2][3] = { 1,2,3,4,5,6 }; 

int arr4[][3] = { 1,2,3,4,5,6 };

以上4种定义方式,利用第二种更加直观,提高代码的可读性
如果对全部元素赋初值,定义数组时对第一维的长度可以不指定,但是第二维的长度不能省略

4.3、字符数组

用来存放字符数据的数组是字符数组,字符数组中的一个元素存放一个字符
定义:

char c[10] = {′I′,′ ′,′a′,′m′,′ ′,′h′,′a′,′p′,′p′,′y′};

赋值:

只能对字符数组的元素赋值,而不能用赋值语句对整个数组赋值

char c[5];
c={′C′,′h′,′i′,′n′,′a′};           //错误,不能对整个数组一次赋值
C[0]=′C′; c[1]=′h′; c[2]=′i′; c[3]=′n′; c[4]=′a′;  //对数组元素赋值,正确

int a[5],b[5]={1,2,3,4,5};
a=b;                                   //错误,不能对整个数组整体赋值
a[0]=b[0];                          //正确,引用数组元素 

4.4、字符串函数

都是C语言中的函数。

字符串连接函数 strcat

字符串复制函数 strcpy

字符串比较函数 strcmp

字符串长度函数 strlen

5、函数

作用:将一段经常使用的代码封装起来,减少重复代码

5.1、函数定义

函数的定义一般主要有5个步骤:

1、返回值类型

2、函数名

3、参数表列

4、函数体语句

5、return 表达式

语法:

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

   函数体语句

   return表达式

}

返回值类型 :一个函数可以返回一个值。在函数定义中
函数名:给函数起个名称
参数列表:使用该函数时,传入的数据
函数体语句:花括号内的代码,函数内需要执行的语句
return表达式: 和返回值类型挂钩,函数执行完后,返回相应的数据
示例:定义一个加法函数,实现两个数相加

//函数定义
int add(int num1, int num2)
{
int sum = num1 + num2;
return sum;
}

5.2、函数调用

功能:使用定义好的函数

语法:函数名(参数)

int result = add(10,20);

函数定义里小括号内称为形参,函数调用时传入的参数称为实参

例如此处的num1,num2 为形参,10,20为实参

函数不能嵌套定义但是可以嵌套调用(常考)

5.3、函数声明

函数的声明可以多次,但是函数的定义只能有一次

//声明可以多次,定义只能一次
//声明
int max(int a, int b);
int max(int a, int b);
//定义
int max(int a, int b)
{
	return a > b ? a : b;
}

int main() {

	int a = 100;
	int b = 200;

	cout << max(a, b) << endl;

	system("pause");

	return 0;
}

5.4、值传递

所谓值传递,即单向传递,就是函数调用时实参将数值传入给形参,而不能由形参传回来给实参。
值传递时,如果形参发生改变,并不会影响实参(值传递时,形参是修饰不了实参的),复制一下。

5.5、函数默认参数

在C++中,函数的形参列表中的形参是可以有默认值的。

语法:返回值类型 函数名 (参数= 默认值){}

int func(int a, int b = 10, int c = 10) {
	return a + b + c;
}

//1. 如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值
//2. 如果函数声明有默认值,函数实现的时候就不能有默认参数
int func2(int a = 10, int b = 10);
int func2(int a, int b) {
	return a + b;
}

int main() {

	cout << "ret = " << func(20, 20) << endl;
	cout << "ret = " << func(100) << endl;

	system("pause");

	return 0;
}

如果某个位置参数有默认值,那么从这个位置往后,从左向右,必须都要有默认值
如果函数声明有默认值,函数实现的时候就不能有默认参数

5.6、函数占位参数

C++中函数的形参列表里可以有占位参数,用来做占位,调用函数时必须填补该位置

语法: 返回值类型 函数名 (数据类型){}

//函数占位参数 ,占位参数也可以有默认参数
void func(int a, int) {
	cout << "this is func" << endl;
}
int main() {

	func(10,10); //占位参数必须填补

	system("pause");

	return 0;
}

5.7、函数重载

作用:函数名可以相同,提高复用性

函数重载满足条件:

  • 函数名称相同
  • 函数参数类型不同 或者 个数不同 或者 顺序不同
    注意: 函数的返回值不可以作为函数重载的条件
//函数重载需要函数都在同一个作用域下
void func()
{
	cout << "func 的调用!" << endl;
}
void func(int a)
{
	cout << "func (int a) 的调用!" << endl;
}
void func(double a)
{
	cout << "func (double a)的调用!" << endl;
}
void func(int a ,double b)
{
	cout << "func (int a ,double b) 的调用!" << endl;
}
void func(double a ,int b)
{
	cout << "func (double a ,int b)的调用!" << endl;
}


//函数返回值不可以作为函数重载条件
//int func(double a, int b)
//{
//	cout << "func (double a ,int b)的调用!" << endl;
//}


int main() {

	func();
	func(10);
	func(3.14);
	func(10,3.14);
	func(3.14 , 10);
	
	system("pause");

	return 0;
}

5.8、重载运算符规则

C++中有以下五个运算符不能重载

成员访问运算符 成员指针访问运算符 域运算符 长度运算符 条件运算符
. .* :: sizeof ?:

重载运算符规则:
重载不能改变运算符运算对象(即操作数)的个数
重载不能改变运算符的优先级别
重载不能改变运算符的结合性
运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也不是友元函数的普通函数

什么时候应该用成员函数方式,什么时候应该用友元函数方式?二者有何区别呢?()

  • 一般将单目运算符重载为成员函数,将双目运算符(二元运算符)重载为友元函数

  • 重载为类的成员函数 - operator 函数有一个参数

  • 重载为类的友元函数 - operator 函数有两个参数

  • 只能将重载 “>>” (流插入运算符)和“<<” (流提取运算符)的函数作为友元函数或者普通函数重载,而不能将它们定义为成员函数,因为参数为两个

  • 类型转换运算符只能作为成员函数重载

  • 单目运算符:只有一个操作数,如 !,-(负号),&,*,++,–

  • 双目运算符:*,/,%,+,-,==,!=,<,>,<=,>=,&&,||

5.9、内联函数

指定内置函数的方法很简单,只需在函数首行的左端加一个关键字inline即可。
inline int max(int a,int b);

使用内置函数可以节省运行时间
只有那些规模较小而又被频繁调用的简单函数,才适合于声明为inline函数。写上不碍事,他会自己判断是否使用,inline是一种建议而不是强制。

5.10、函数模板

语法:

template<typename T>
函数声明或定义

解释:
template — 声明创建模板
typename — 表面其后面的符号是一种数据类型,可以用class代替
T — 通用的数据类型,名称可以替换,通常为大写字母
只适用于函数体相同、函数的参数个数相同而类型不同的情况,如果参数的个数不同,则不能用函数模板。

6、指针

指针的作用: 可以通过指针间接访问内存

6.1、指针变量

指针变量定义语法: 数据类型 * 变量名;

请看下方代码示例,理解指针变量的定义与使用.

int main() {

	//1、指针的定义
	int a = 10; //定义整型变量a
	
	//指针定义语法: 数据类型 * 变量名 ;
	int * p;

	//指针变量赋值
	p = &a; //指针指向变量a的地址
	cout << &a << endl; //打印数据a的地址
	cout << p << endl;  //打印指针变量p
    //0073F8BC
    //0073F8BC

	//2、指针的使用
	//通过*操作指针变量指向的内存
	cout << "*p = " << *p << endl;
    // *p = 10

	system("pause");

	return 0;
}

指针变量和普通变量的区别

普通变量存放的是数据,指针变量存放的是地址
指针变量可以通过" * "操作符,操作指针变量指向的内存空间,这个过程称为解引用

  • 总结1: 我们可以通过 & 符号 获取变量的地址

  • 总结2:利用指针可以记录地址

  • 总结3:对指针变量解引用,可以操作指针指向的内存

  • 总结4:所有指针类型在32位操作系统下是4个字节(了解)

6.2、const修饰指针

const修饰指针有三种情况

  • const修饰指针 — 常量指针
  • const修饰常量 — 指针常量
  • const既修饰指针,又修饰常量
int main() {

	int a = 10;
	int b = 10;

	//const修饰的是指针,指针指向可以改,指针指向的值不可以更改
	const int * p1 = &a; 
	p1 = &b; //正确
	//*p1 = 100;  报错
	

	//const修饰的是常量,指针指向不可以改,指针指向的值可以更改
	int * const p2 = &a;
	//p2 = &b; //错误
	*p2 = 100; //正确

    //const既修饰指针又修饰常量
	const int * const p3 = &a;
	//p3 = &b; //错误
	//*p3 = 100; //错误

	system("pause");

	return 0;
}    

6.3、指针和数组

作用:利用指针访问数组中元素

C++规定,数组名就是数组的起始地址
数组的指针就是数组的起始地址
数组名可以作函数的实参和形参,传递的是数组的地址

int main() {

	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	int * p = arr;  //指向数组的指针

	cout << "第一个元素: " << arr[0] << endl; 		//1
	cout << "指针访问第一个元素: " << *p << endl;	  //1

	for (int i = 0; i < 10; i++)
	{
		//利用指针遍历数组
		cout << *p << endl;
		p++;
	}

	system("pause");

	return 0;
}

6.4、指针和函数

作用:利用指针作函数参数,可以修改实参的值(地址传递)

//值传递
void swap1(int a ,int b)
{
	int temp = a;
	a = b; 
	b = temp;
}
//地址传递
void swap2(int * p1, int *p2)
{
	int temp = *p1;
	*p1 = *p2;
	*p2 = temp;
}

int main() {

	int a = 10;
	int b = 20;
	swap1(a, b); // 值传递不会改变实参

	swap2(&a, &b); //地址传递会改变实参

	cout << "a = " << a << endl;

	cout << "b = " << b << endl;

	system("pause");

	return 0;
}
int a[10];
		
int *p = &a[0];	 // 等价于 int *p = a;	
*p = 1; 	     // 等价于 a[0] = 1;
*(p+1) = 2;		 // 等价于 a[1] = 2;
// 所以 *(p+1) = a[1]; *(p+2) = a[2];
C++规定, p+1 指向数组的 下一个元素
void main()
{
    int array[10];
    // 用数组名作形参,因为接收的是地址,所以可以不指定具体的元素个数
    f(array,10);
}

// 形参数组
f(int arr[],int n)
{
    ....
}
void main()
{
    int a[10];
    // 实参数组
    f(a,10);
}
// 形参指针
f(int *x,int n)
{
    ...
}

总结:如果不想修改实参,就用值传递,如果想修改实参,就用地址传递

6.4、返回指针值的函数

返回指针值的函数简称指针函数。
定义指针函数的一般形式为:

// 类型名 * 函数名(参数列表)
int  * a(int x,int y);

7、引用

作用: 给变量起别名

语法: 数据类型 &别名 = 原名

int main() {

	int a = 10;
	int &b = a;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
    // 10
    // 10

	b = 100;

	cout << "a = " << a << endl;
	cout << "b = " << b << endl;
    // 100
    // 100

	system("pause");

	return 0;
}

7.1、引用注意事项

引用必须初始化

int &c; // 错误,引用必须初始化

在声明一个引用后,不能再使之作为另一变量的引用

7.2、引用做函数参数

作用:函数传参时,可以利用引用的技术让形参修饰实参

优点:可以简化指针修改实参

通过引用参数产生的效果同按地址传递是一样的。引用的语法更清楚简单

//1. 值传递
void mySwap01(int a, int b) {
	int temp = a;
	a = b;
	b = temp;
}

//2. 地址传递
void mySwap02(int* a, int* b) {
	int temp = *a;
	*a = *b;
	*b = temp;
}
//参数:把地址传进去,用指针接收

//3. 引用传递
void mySwap03(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}
//参数:别名,下面的a是上面的a的别名,用别名操作修改可原名操作修改是一样的
int main() {

	int a = 10;
	int b = 20;
    // 值传递,形参不会修饰实参
	mySwap01(a, b);
	cout << "a:" << a << " b:" << b << endl;
    // a:10 b:20

    // 地址传递,形参会修饰实参
	mySwap02(&a, &b);
	cout << "a:" << a << " b:" << b << endl;
    // a:20 b:10

    // 引用传递,形参会修饰实参
	mySwap03(a, b);
	cout << "a:" << a << " b:" << b << endl;
    // a:20 b:10

	system("pause");

	return 0;
}

7.3、引用做函数返回值

作用:引用是可以作为函数的返回值存在的

//数据类型后加&,相当于用引用的方式返回 
int& test02() {
    // 必须使用静态变量,需加 static 关键字
	static int a = 20;
	return a;
}


int main(){
    int& ref2 = test02();
    system("pause");
    return 0;
}

8、类和对象

8.1、struct和class区别

在C++中 struct和class唯一的区别就在于 默认的访问权限不同

区别:

  • struct 默认权限为公共
  • class 默认权限为私有

8.1、构造函数和析构函数

构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作
构造函数语法:类名(){}(构造和析构很容易出选择题,特点要记住)

构造函数,没有返回值也不写void
构造函数的名字必须与类名相同
构造函数可以有参数,因此可以发生重载
程序在调用对象时候会自动调用构造函数,无须手动调用,而且只会调用一次(构造函数不需用户调用,也不能被用户调用)
析构函数语法: ~类名(){}

析构函数,没有返回值也不写void
函数名称与类名相同,在名称前加上符号~
析构函数不可以有参数,因此不可以发生重载
程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次

class Person
{
public:
	//构造函数
	Person()
	{
		cout << "Person的构造函数调用" << endl;
	}
	//析构函数
	~Person()
	{
		cout << "Person的析构函数调用" << endl;
	}

};

void test01()
{
	Person p; //在栈上的数据,test01()执行完毕后,释放这个对象
}

int main() {
	
	test01();

	system("pause");

	return 0;
}

8.3、构造函数分类与调用

构造函数按参数分为: 有参构造和无参构造

调用方式:括号法

class Person {
public:
	//无参(默认)构造函数
	Person() {
		cout << "无参构造函数!" << endl;
	}
	//有参构造函数
	Person(int a) {
		age = a;
		cout << "有参构造函数!" << endl;
	}
    //析构函数
	~Person() {
		cout << "析构函数!" << endl;
	}
public:
	int age;
};

//2、构造函数的调用
//调用无参构造函数
void test01() {
	Person p; //调用无参构造函数
}

//调用有参的构造函数
void test02() {

	// 括号法,常用
	Person p1(10);
}

尽管在一个类中可以包含多个构造函数,但是对于每一个对象来说,建立对象时只执行其中一个构造函数,并非每个构造函数都被执行

8.4、初始化列表

C++提供了初始化列表语法,用来初始化属性
语法:构造函数():属性1(值1),属性2(值2)… {}

class Person {
public:

	传统方式初始化
	//Person(int a, int b, int c) {
	//	m_A = a;
	//	m_B = b;
	//	m_C = c;
	//}

	//初始化列表方式初始化
	Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {}
	void PrintPerson() {
		cout << "mA:" << m_A << endl;
		cout << "mB:" << m_B << endl;
		cout << "mC:" << m_C << endl;
	}
private:
	int m_A;
	int m_B;
	int m_C;
};

int main() {

	Person p(1, 2, 3);
	p.PrintPerson();


	system("pause");

	return 0;
}

8.5、类对象作为类成员

C++类中的成员可以是另一个类的对象,我们称该成员为 对象成员

例如:

class A {}
class B
{
    A a;
}

B类中有对象A作为成员,A为对象成员
那么当创建B对象时,A与B的构造和析构的顺序是谁先谁后?
先调用对象成员的构造,再调用本类构造(如上例中,先调用A的构造函数)
析构顺序与构造相反

8.6、静态成员

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员

静态成员分为:

静态成员变量

  • 所有对象共享同一份数据
  • 在编译阶段分配内存
  • 类内声明,类外初始化
    静态成员函数
  • 所有对象共享同一个函数
  • 静态成员函数只能访问静态成员变量
    **示例1 **:静态成员变量
class Person
{
	
public:

	static int m_A; //静态成员变量

	//静态成员变量特点:
	//1 在编译阶段分配内存
	//2 类内声明,类外初始化
	//3 所有对象共享同一份数据

private:
	static int m_B; //静态成员变量也是有访问权限的
};
int Person::m_A = 10;
int Person::m_B = 10;

void test01()
{
	//静态成员变量两种访问方式

	//1、通过对象
	Person p1;
	p1.m_A = 100;
	cout << "p1.m_A = " << p1.m_A << endl;

	Person p2;
	p2.m_A = 200;
	cout << "p1.m_A = " << p1.m_A << endl; //共享同一份数据
	cout << "p2.m_A = " << p2.m_A << endl;

	//2、通过类名
	cout << "m_A = " << Person::m_A << endl;


	//cout << "m_B = " << Person::m_B << endl; //私有权限访问不到
}

int main() {

	test01();

	system("pause");

	return 0;
}

示例2:静态成员函数

class Person
{

public:

	//静态成员函数特点:
	//1 程序共享一个函数
	//2 静态成员函数只能访问静态成员变量
	
	static void func()
	{
		cout << "func调用" << endl;
		m_A = 100;
		//m_B = 100; //错误,不可以访问非静态成员变量
	}

	static int m_A; //静态成员变量
	int m_B; // 
private:

	//静态成员函数也是有访问权限的
	static void func2()
	{
		cout << "func2调用" << endl;
	}
};
int Person::m_A = 10;


void test01()
{
	//静态成员变量两种访问方式

	//1、通过对象
	Person p1;
	p1.func();

	//2、通过类名
	Person::func();


	//Person::func2(); //私有权限访问不到
}

int main() {

	test01();

	system("pause");

	return 0;
}

8.7、const修饰成员函数

常函数:

  • 成员函数后加const后我们称为这个函数为常函数
  • 常函数内不可以修改成员属性

常对象:

  • 声明对象前加const称该对象为常对象
  • 常对象只能调用常函数

8.8、const型数据小结

形式 含义
Time const t1 t1 是常对象,其值在任何情况下都不能改变
void Time::fun() const fun 是 Time类中的常成员函数,可以引用,但不能修改本类中的数据成员
Time * const p p 是指向Time对象的常指针,P的值不能改变
const Time *p p是指向 Time 类常对象的指针,其指向的类对象的值不能通过指针来改变
Time &t1 = t; t1是Time类对象t的引用,二者指向同一段内存空间

9、继承

继承的好处:可以减少重复的代码

继承的语法:class 子类 : 继承方式 父类

class A : public B;

A 类称为子类 或 派生类

B 类称为父类 或 基类

9.1、继承方式

继承方式一共有三种:

  • 公共继承
  • 保护继承
  • 私有继承

简单的说:

公共继承:基类的公用成员和保护成员在派生类中保持原有访问属性,其私有成员仍为基类私有。
私有继承:基类的公用成员和保护成员在派生类中成了私有成员。其私有成员仍为基类私有
保护继承:基类的公用成员和保护成员在派生类中成了保护成员,其私有成员仍为基类私有。

9.2、构造和析构函数

构造函数的主要作用是对数据成员初始化

派生类是不能继承基类的析构函数,也需要通过派生类的析构函数去调用基类的析构函数

继承中 先调用父类构造函数,再调用子类构造函数,析构顺序与构造相反

9.3、不能继承

C++中,不能被派生类继承的是:构造函数

9.4、继承特点

单继承:一个派生类只从一个基类派生

多继承:一个派生类有两个或多个基类的称为多重继承

10、多态

多态性是指具有不同功能的函数可以用同一个函数名,这样就可以用一个函数名调用不同内容的函数

多态分为两类

  • 静态多态: 函数重载 和 运算符重载属于静态多态,复用函数名
  • 动态多态: 派生类和虚函数(virtual function)实现运行时多态

10.1、虚函数

什么是虚函数?

在基类用 virtual 声明成员函数为虚函数

虚函数的作用:
虚函数的作用是允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数
虚函数的使用方法:

在基类用 virtual 声明成员函数为虚函数。这样就可以在派生类中重新定义此函数,为它赋予新的功能,并能方便地被调用
在类外定义虚函数时,不必再加virtual
在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体
C++规定,当一个成员函数被声明为虚函数后,其派生类中的同名函数都自动成为虚函数。因此在派生类重新声明该虚函数时,可以加virtual,也可以不加,但习惯上一般在每一层声明该函数时都加virtual,使程序更加清晰

class Animal
{
public:
	//Speak函数就是虚函数
	//函数前面加上virtual关键字,变成虚函数,那么编译器在编译的时候就不能确定函数调用了。
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Cat :public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

class Dog :public Animal
{
public:

	void speak()
	{
		cout << "小狗在说话" << endl;
	}

};
//我们希望传入什么对象,那么就调用什么对象的函数
//如果函数地址在编译阶段就能确定,那么静态联编
//如果函数地址在运行阶段才能确定,就是动态联编

void DoSpeak(Animal & animal)
{
	animal.speak();
}

//多态满足条件: 
//1、有继承关系
//2、子类重写父类中的虚函数
//多态使用:
//父类指针或引用指向子类对象

void test01()
{
	Cat cat;
	DoSpeak(cat);


	Dog dog;
	DoSpeak(dog);
}


int main() {

	test01();

	system("pause");

	return 0;
}

多态满足条件

  • 有继承关系
  • 子类重写父类中的虚函数
    纯虚函数
  • 纯虚函数是在声明虚函数时被“初始化”为0的函数。声明纯虚函数的一般形式是

virtual 函数类型 函数名 (参数表列) =0;

  • 纯虚函数没有函数体

  • 最后面的 =0 ,并不表示函数返回值为0,它只告诉编译系统“老子是纯虚函数”

纯虚函数只有函数的名字而不具备函数的功能,不能被调用

抽象类

  • 凡是包含纯虚函数的类都是抽象类

  • 一个基类如果包含一个或一个以上纯虚函数,就是抽象基类。抽象基类不能也不必要定义对象、

11、文件操作

C++中对文件操作需要包含头文件 < fstream >

文件类型分为两种:

  • 文本文件 - 文件以文本的ASCII码形式存储在计算机中

  • 二进制文件 - 文件以文本的二进制形式存储在计算机中,用户一般不能直接读懂它们
    操作文件的三大类:

  • ofstream:写操作

  • ifstream: 读操作

  • fstream : 读写操作

11.1、文本文件

11.1.1写文件

写文件步骤如下:

包含头文件

#include <fstream>

创建流对象

ofstream ofs;

打开文件

ofs.open(“文件路径”,打开方式);

写数据

ofs << “写入的数据”;

关闭文件

ofs.close();

文件打开方式:

打开方式 解释

ios::in 为读文件而打开文件
ios::out 为写文件而打开文件
ios::ate 初始位置:文件尾
ios::app 追加方式写文件
ios::trunc 如果文件存在先删除,再创建
ios::binary 二进制方式
注意: 文件打开方式可以配合使用,利用|操作符

**例如:**用二进制方式写文件 ios::binary | ios:: out

示例:

#include <fstream>

void test01()
{
	ofstream ofs;
	ofs.open("test.txt", ios::out);

	ofs << "姓名:张三" << endl;
	ofs << "性别:男" << endl;
	ofs << "年龄:18" << endl;

	ofs.close();
}

int main() {

	test01();

	system("pause");

	return 0;
}

总结:

  • 文件操作必须包含头文件 fstream
  • 读文件可以利用 ofstream ,或者fstream类
  • 打开文件时候需要指定操作文件的路径,以及打开方式
  • 利用<<可以向文件中写数据
  • 操作完毕,要关闭文件

11.1.2读文件

读文件与写文件步骤相似,但是读取方式相对于比较多

读文件步骤如下:

包含头文件

#include <fstream>

创建流对象

ifstream ifs;

打开文件并判断文件是否打开成功

ifs.open(“文件路径”,打开方式);

读数据

四种方式读取

关闭文件

ifs.close();

示例:

#include <fstream>
#include <string>
void test01()
{
	ifstream ifs;
	ifs.open("test.txt", ios::in);

	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}

	//第一种方式
	//char buf[1024] = { 0 };
	//while (ifs >> buf)
	//{
	//	cout << buf << endl;
	//}

	//第二种
	//char buf[1024] = { 0 };
	//while (ifs.getline(buf,sizeof(buf)))
	//{
	//	cout << buf << endl;
	//}

	//第三种
	//string buf;
	//while (getline(ifs, buf))
	//{
	//	cout << buf << endl;
	//}

	char c;
	while ((c = ifs.get()) != EOF)
	{
		cout << c;
	}

	ifs.close();


}

int main() {

	test01();

	system("pause");

	return 0;
}

总结:

  • 读文件可以利用 ifstream ,或者fstream类
  • 利用is_open函数可以判断文件是否打开成功
  • close 关闭文件

11.2 二进制文件

以二进制的方式对文件进行读写操作

打开方式要指定为 ios::binary

11.2.1 写文件

二进制方式写文件主要利用流对象调用成员函数write

函数原型 :ostream& write(const char * buffer,int len);

参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数

示例:

#include <fstream>
#include <string>

class Person
{
public:
	char m_Name[64];
	int m_Age;
};

//二进制文件  写文件
void test01()
{
	//1、包含头文件

	//2、创建输出流对象
	ofstream ofs("person.txt", ios::out | ios::binary);
	
	//3、打开文件
	//ofs.open("person.txt", ios::out | ios::binary);

	Person p = {"张三"  , 18};

	//4、写文件
	ofs.write((const char *)&p, sizeof(p));

	//5、关闭文件
	ofs.close();
}

int main() {

	test01();

	system("pause");

	return 0;
}

总结:

  • 文件输出流对象 可以通过write函数,以二进制方式写数据

11.2.2 读文件

二进制方式读文件主要利用流对象调用成员函数read

函数原型:istream& read(char *buffer,int len);

参数解释:字符指针buffer指向内存中一段存储空间。len是读写的字节数

示例:

#include <fstream>
#include <string>

class Person
{
public:
	char m_Name[64];
	int m_Age;
};

void test01()
{
	ifstream ifs("person.txt", ios::in | ios::binary);
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
	}

	Person p;
	ifs.read((char *)&p, sizeof(p));

	cout << "姓名: " << p.m_Name << " 年龄: " << p.m_Age << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

文件输入流对象 可以通过read函数,以二进制方式读数据

12、输入输出流

标准输出流:cout 、cerr、clog

cerr、clog流对象都是标准错误流,都是在终端显示器上显示出错信息

  • 标准输入流:cin、get、getline

  • get函数读入一个字符,getline读入一行字符

  • eof函数:文件结束

  • peek函数:peek函数的作用是观测下一个字符。

  • putback函数:其作用是将前面用get或getline函数从输入流中读取的字符ch返回到输入流,插入到当前指针位置,以供后面读取

  • ignore函数:函数作用是跳过输入流中n个字符,或在遇到指定的终止字符时提前结束

13、异常

C++处理异常的机制是由3个部分组成的,即检查(try)、抛出(throw)和捕捉(catch)。

命名空间的作用是建立一些互相分隔的作用域,把一些全局实体分隔开来,以免产生名字冲突

课件速过:

1 第一章

1.1 C++初步认识

C语言仅支持面向过程编程
C++支持面向过程程、面向对象编程
就面向过程编程而言,C++和C几乎是一样的。

C++语言特点

  • C++全面容C语言
  • 用C++写的程序可读性更好,代码结构更为合理
  • 生成代码质量高,运行效仅比汇语言慢10%~20%
  • 从开发时间、费用到形成软件的可重用性可扩充性可维护性可靠性等方面有很大提高,得大中型款件开发变得容易很多
  • 支持面向对象设计,可方便地构造出模拟现实问题的实体和操作
    C++应用领域
  • 服务端开发
  • 游戏开发
  • 数字图像处理:AutoCAD OpenCV
  • 虚拟现实
  • 设备驱动程序
  • 嵌入式系统开发

1.用C++语言编写程序
2.对源程序进行编译
3.将目标文件连接
4.运行程序
5.分析运行结果+

例1.2 求两数之和

#include <iostream>

using namespace std;

int main()
{
    int a, b, sum;
    cin >> a >> b;
    sum = a + b;
    cout << "a + b = " << sum << endl;
    return 0;
}

例1.5 用cin和cout实现数据的输入输出

#include <iostream>

using namespace std;

int main()
{
    cout << "Please enter your name and age:" << endl;
    char name[10];
    int age;
    cin >> name;
    cin >> age;
    cout << "your name is " << name << endl;
    cout << "your age is  " << age << endl;
    return 0;
}

其实,C++编译时,只检查数的数据类型,所以返回值的类型不能算作重载。
例1.3 从键盘中输入两个数a和b,求两个数的最大数。

#include <iostream>

using namespace std;

int main()
{
    int max(int x, int y);
    int a, b, c;
    cout << "请输入两个整数:" << endl;
    cin >> a >> b;
    c = max(a, b);
    cout << "max = " << c << endl;
    return 0;
}

int max(int x, int y)
{
    int m;
    m = x > y ? x : y;
    return m;
}

1.2 函数的重载

  • C++多态性体现之一
  • C++允许在同一个域中用一个函数名定义多个函数,这些函数的参数个数、参数类型不相同。
    用一个函数名实现不同的功能,就是函数的重载。

例1.6 设计程序计算三个数中的最大数

#include <iostream>

using namespace std;

int max(int a, int b, int c)
{
    if(b > a) a = b;
    if(c > a) a = c;
    return a;
}

int max(float a, float b, float c)
{
    if(b > a) a = b;
    if(c > a) a = c;
    return a;
}

int max(long a, long b, long c)
{
    if(b > a) a = b;
    if(c > a) a = c;
    return a;
}
int main()
{
    int a,b,c;
    float d,e,f;
    long g,h,i;
    cin >> a >> b >> c;
    cin >> d >> e >> f;
    cin >> g >> h >> i;
    int m;
    m = max(a, b, c);
    cout << "max_i=" << m << endl;
    float n;
    n = max(d,e,f);
    cout << "max_f=" << n << endl;
    long int p;
    p = max(g,h,i);
    cout << "max_l=" << p << endl;
    return 0;
}

参数的个数也可以进行重载。
例1.8 将1.6程序改为通过函数模板实现

#include <iostream>

using namespace std;

template<typename T>
T max(T a, T b, T c)
{
    if(b > a) a = b;
    if(c > a) a = c;
    return a;
}

int main()
{
    int a,b,c;
    float d,e,f;
    long g,h,i;
    cin >> a >> b >> c;
    cin >> d >> e >> f;
    cin >> g >> h >> i;
    int m;
    m = max(a, b, c);
    cout << "max_i=" << m << endl;
    float n;
    n = max(d,e,f);
    cout << "max_f=" << n << endl;
    long int p;
    p = max(g,h,i);
    cout << "max_l=" << p << endl;
    return 0;
}

函数模板
只适用于函数参数的个数相同而类型不同,并且函数体相同的情况,如果函数的参数个数不同,则不能用函数模板。
默认参数:上面也讲过了。

  • 实参按从左到右的顺序被依次赋值给形参,不会跳过任何形参。
  • 函数中形参必须从右向左设置默认值。
  • 指定默认的参数必须放在形参列表的最石端
    注意
  1. 必须在函数调用前将默认值信息通知编译系统若函数声明和定义时给了不同默认值,以在先的函数声明时默认值为准;
  2. 一个函数名不能同时用于重载函数和带默认形参值的函数当调用函数时,少写一个参数,将出现二义性。
    例:intmax(inta,intb,intc=100)
    int max(inta,int b)
    max(5,23); //调用哪一个?

1.3 变量的引用

引用的概念:给一个变量起一个别名。
引用的简单使用:

#include <iostream>

using namespace std;

int main()
{
    int a = 10;
    int &b = a;
    a = a * a;
    cout << a << " " << b << endl; // 100 100
    b = b / 5;
    cout << b << " " << a << endl;// 20 20
    return 0;
}

在这里插入图片描述
引用的简单说明
在这里插入图片描述
形参:
出现在函数定义中,
在整个函数体内都可以使用,
离开该函数则不能使用。
只有在被调用时才分配内存单元
在调用结束时,即释放所分配的内存单元
(形参只在函数内部有效
实参:
出现在主调函数中,
进入被调函数后,实参变量也不能使用。
函数调用时,必须有确定的值,把这些值传送给形参。(应先赋值、输入等办法使参数获得确定值)

函数参数的三种传递方式:
变量名作为实参:单向传递数据,形参对实参无影响
传递变量的指针:单向传递指针,形参通过改变指针指向的值,改变实参指针对应变量的值。
传送变量的别名:形参为实参变量的别名,共用同一存储空间,形参实参的值同时改变 (C++扩充)
有些过去只能用指针解决的问题,现在可以用引用解决

2 类和对象的特性

2.1 面向对象的程序设计

封装 继承 多态
封装性是面向对象程序设计的重要特点,两个含义:
①各对象相互独立,互不干扰,程序中的基本单位
②信息屏蔽:某些部分对外隐蔽,只留下与外界接口接收消息外界只需了解对象接口。
C++对象中公有函数是对象的对外接口
外界调用公有函数,访问对象中的数据成员,完成指定的操作
继承
继承机制:
已建A类,要建B类,
(B类与A类基本相同,比A类多一些属性和行为
只需在A类的基础上添加新内容即可
C++具有继承机制:(软件重用,缩短软件开发周期)
在已有类的基础上建立新类
已有类:自己过去建立的类或其他人放在类库中的类
多态性
多个相似而不完全相同的对象,
收到外界同一个消息,各自执行不同的操作。
在windows中,用鼠标双击一个文件对象时,
可执行文件,则执行文件程序;
文本文件,则启动编辑器来打开。
C++多态性:增加程序灵活性。
由继承而产生的相关不同类,对象对同一个消息会作出不同的响应

2.2. 类的声明和对象的定义

类是抽象的,不占用内存空间
对象是具体的,占用内存空间

2.3 类的成员

  • 成员函数:可以访问本类的所有成员
  • 私有成员函数:只能被本类的其他成员函数调用,不能被类外调用。

inline
系统调用函数的时间开销比较大
调用一个函数的时间开销远远大于小规模函数体中全部语句的运行时间
为减少时间开销,将类的成员函数作为内置函数
把函数代码复制插入程序的调用点。

说明:
(1)成员函数在类内或类外定义代码段存储方式相同,都不占用对象的存储空间
(2)inline函数只影响程序执行效率,与成员函数是否占用对象存储空间没有关系。依然不占对象存储空间

C++编译器给每个“成员函数” 增加一个隐藏指针 (this指针),指向不同对象。
调用对象stdu1成员函数时,this指针就指向stdu1, 成员函数访问stdu1的成员。
调用对象stdu2成员函数时,this指针就指向stdu2,成员函数访问stdu2的成员。
一点小问题:

  1. 类是抽象的,不占存储空间;对象是具体的,占存储空间。
  2. 声明类的关键字是class。类体中的成员访问属性默认为私有的。
  3. 在C++中,每个对象都是由数据、函数两部分组成的。
  4. C++提供继承机制,可以很方便的利用一个已有的类建立一个新类。
  5. 如果有几个相似而不完全相同的对象,要求在向他们发出同一消息时,他们的反应各不相同,执行不同的操作,这种情况叫做多态。
  6. 应该养成一种习惯:每一种成员访问限定符在类定义体中 出现1次。
  7. 类的成员函数是函数的一种,它与普通函数的区别是:他可以被指定为私有、公用和受保护类型,出现在类体中,它是属于一个类的成员。
  8. 关于对象的成员存储方式的说法,正确的是:类的成员函数不论是在类内还是类外定义,存储方式都相同,不占对象的存储空间;对象的数据成员都占系统存储空间;用类定义对象时,系统为每一个对象分配存储空间。

3 类和对象的简单利用

思考:既然成员函数都共享存储空间,“对象**的成员函数”的说法正确吗?

(1)成员函数的是类的功能,同一类的对象都有该功能;
(2)从逻辑角度:“对象**的成员函数”,
成员函数和数据封装在一个对象中,
只允许对象中的成员函数访问同一对象的私有数据
从内存管理的角度,类的成员函数代码存放在同一个地方并不矛盾。

3.1 如何访问对象成员

用点访问。

class Time
{
public:
	int hour;
	int minute;
};
Time t, *p;
p = &t;
coput << p->hour << endl;

在这里插入图片描述
思考:如果函数定义和声明时的默认参数值不同,怎么办?
以声明为准,只在声明时指定默认值。
例题2.3:将2.2改用含成员函数的类实现

#include <iostream>

using namespace std;

class Time
{
public:
    void set_time();
    void show_time();
private:
    int hour;
    int minute;
    int sec;
};

void Time::set_time()
{
    cin >> hour;
    cin >> minute;
    cin >> sec;
}
void Time::show_time()
{
    cout << hour << ":" << minute << ":" << sec << endl;
}
int main()
{
    Time t1;
    t1.set_time();
    t1.show_time();

    return 0;
}


例题2.4在整型数组中找最大值

#include <iostream>

using namespace std;

class Array_max
{
public:
    void set_value();
    void max_value();
    void show_value();
private:
    int array[10];
    int max;
};

void Array_max::set_value()
{
    for(int i = 0; i < 10; i ++)
        cin >> array[i];
}

void Array_max::max_value()
{
    max = array[0];
    for (int i = 0; i < 10; i ++)
    {
        if (array[i] > max)
            max = array[i];
    }
}

void Array_max::show_value()
{
    cout << "max value is: "  << max << endl;
}

int main()
{
    Array_max arrmax;
    arrmax.set_value();
    arrmax.max_value();
    arrmax.show_value();

    return 0;
}

3.2 类的封装性和信息隐蔽

C++通过类实现封装性

  • 一般将数据成员指定为私有,与外界隔离
  • 将成员函数指定为公有,外界通过公有函数对数据成员的访问。
  • 外界与对象的唯一联系就是调用公有成员函数。
  • 公有成员函数是用户使用类的公用接口
    接口与实现分离
  • 用户调用公有成员函数现某些功能,
  • 用户只需了解公有成员函数的功能
  • 不必了解这些功能是怎样实现的
    类的公有接口与私有实现的信息隐:
  • 防止用户任意修改公有成员函数不让用户看到公有成员函代码
  • 数据私有,实现操作的细节对用户隐蔽,称为私有实现

信息隐蔽优点:程序设计、修改和调试方便和简单
(1)修改或扩充功能,只需修改类有关数据成员和成员函数。只要类接口不变,对私有实现的修改不会影响程序的其他部分
(2)编译时类数据读写有错,只需检查类中访问这些数据的成员函数。
在这里插入图片描述

刷题

  1. ::运算符不能重载;类型运算符只能作为成员函数重载。“?:”、“.”、“::”、“sizeof”和”.*”
  2. 将运算符重载为类成员函数时,其参数表中没有参数,说明该运算符是一元运算符。
  3. 虚基类的描述:1.使用虚基类可以消除多继承产生的二义性;2.构造派生类对象时,虚基类的构造函数只能被调用一次;3.建立派生类对象时,首先调用虚基类的构造函数。
  4. 构造函数在创建对象时由系统自动调用。
  5. eof()函数可以检测是否到达文件尾;对磁盘文件进行流操作时,必须包含头文件 fstream;以 ios_base::out 模式打开的文件不存在时,将自动建立一个新文件。
  6. 标识符命名规则。
  7. 子类继承父类的数据成员。
  8. 运算符函数:1.运算符函数的名称总是以 operator 为前缀;2.运算符函数的参数可以是对象;3.运算符函数的参数可以是类的成员函数也可以不是;4.在表达式中使用重载的运算符相当于调用运算符重载函数。
  9. 与++a等效的运算符函数调用形式为a.operator++()
  10. 建立一个对象时,系统自动调用构造函数。
  11. 通过派生类的对象可直接访问其公有继承基类的公有成员。
  12. 1.不能重载的运算符:长度运算符sizeof、条件运算符: ?、成员选择符.和域解析运算符::不能被重载! 2.重载不能改变运算符的优先级、结合性和操作数3.运算符重载函数不能有默认的参数。
  13. 字符串用双引号
  14. a++本身为a
  15. 八进制中不能有大于等于八的数字。
  16. 一个类的友元函数能够访问该类的所有成员。
  17. C++中的模块包括函数模块和类模块。
  18. 用C++编写的程序是一个源程序。
  19. 在面向对象程序设计中,实现信息隐蔽是靠对象的封装。
  20. 如果一个类至少有一个纯虚函数,那么就称该类为抽象类。
  21. C++类体系中,不能被派生类继承的有构造函数。
  22. 虚基类的声明:class B: virtual public A
  23. 派生类的虚函数与基类中对应的虚函数具有相同的参数个数和类型。
  24. 有关类的多态性不正确的说法是同类对象的类定义。
  25. 有语句定义char a[16];如果从键盘输入一个含空格的字串,可用语句cin.get(a,16)。
  26. I/O流操作文件时,需要包含fstream.h文件。
  27. 当要建立一个文件,并从其中读数据和向其中写数据时,应该建立下面哪种流类的对象fstream
  28. cin/cout 是 I/O 流库预定义的对象。
  29. 运算符重载函数通常是类的成员函数和友元函数。
  30. 编译程序的功能是将高级语言程序转换为目标程序。
  31. 类的概念是对象的抽象。
  32. 关于文件操作不正确的是:文件读写过程中,程序将直接与磁盘文件进行数据交换。
  33. 下列函数中, put()是对文件进行写操作的。
  34. 打开文件的目的是使文件对象与磁盘文件建立联系.
  35. 语句 ofstream f(”SALARY.DAT”,ios::app )的功能是建立流对象 f,并试图打开文件 SALARY.DAT 与 f 关联,而且若文件存在,将文件指针定位于文件尾;若文件不存在,建立一个新文件.
  36. C++流中重载了运算符<<,它是一个用于输出操作的成员函数。
  37. 在 ios 中提供控制的标志中, hex是转换为十六进制形成的标志位。
  38. 使用 setw()对数据进行格式输出时,应包含iomanip.h文件。
  39. 如果没有显式定义构造函数(包括复制构造函数), C++编译器就隐式定义默认的构造函数.
  40. 成员函数不一定是内联函数。
  41. 析构函数不能有参数。
  42. 友元函数破坏了类的封装性和隐藏性。
  43. 静态数据成员是类的所有对象共享的数据。
  44. 构造函数特征:1.构造函数的函数名与类名相同2.构造函数可以重载3.构造函数可以设置默认参数
  45. 不同数据类型相加,提升为相同的数据类型,较宽的数据类型。
  46. 多重继承中可以通过虚基类防止二义性问题、
  47. 1.继承分为多重继承和单继承2. 对象间通信靠传递消息实现3.类是具有共同属性、共同方法的对象的集合4.在外面看不到对象的内部特征是基于对象的"封装性"这个特征
  48. 面向对象方法的主要特征为多态性,继承性和封装性。
  49. 重载函数中编译是根据参数表进行选择的。
  50. 1)类之间应具有共享的特征;2)类之间应具有差别或新增特征;3)类之间是一种层次结构;
  51. 在类型转换符函数的定义中不需要声明返回类型。
  52. 纯虚函数 virtual void tt()=0;
  53. 子类可以继承父类中除构造和析构函数之外的所有成员。
  54. 赋值兼容规则不适用于多重继承的组合。
  55. 设置虚基类的目的是 消除二义性。
  56. 在多重继承中,公有派生和私有派生对于基类成员在派生类中的访问性与单一继承的规则相同。
  57. 在 C++中,类与类之间的继承关系具有传递性。
  58. C++规定=,[ ],(),->这四个运算符只能被重载为类的非静态成员函数,其他的可以被友元重载,主要是因为其他的运算符重载函数都会根据参数类型或数目进行精确匹配,这四个不具有这种检查的功能,用友元定义就会出错。
  59. 与键盘、屏幕、打印机和通信端口的交互都可以通过流类来实现。
  60. ±*、既可重载为一元运算符,又可重载为二元运算符。
  61. 运算对象必须为整型数的运算符是%。
  62. a 类为 b 类的友元类,则 a 类中的所有函数就可以访问 b 类中的所有成员、
  63. 二进制文件中每字节数据都没有用 ASCII 码表示、
  64. 磁盘文件操作时,打开磁盘文件的访问方式常量中, app是以追加方式打开文件的。
  65. 当使用 ifstream 流定义一个流对象并打开一个磁盘文件时,文件的隐含打开方式为ios::in。
  66. 常量不能进行++运算。
  67. 字符常量与字符串常量的描述:1.两者表示形式不同:前者使用单引号,后者使用双引号2.两者存放方式不同:前者存放在字符变量中,后者存放在字符数组或字符指针指定的位置3.存放字符串常量时系统会自动加一个结束符’‘\0’'。
  68. 只有字符串常量才能参与连接运算。
  69. Visual C++中打开一个已存在的项目,应打开其中后缀名为dsw的文件。
  70. 已知 f1(int)是类 A 的公有成员函数, p 是指向成员函数 f1()的指针,采用p = A::f1是正确的。
  71. 控制格式 I/O 的操作中, setw()是设置域宽的。
  72. 实现运行时的多态性要使用虚函数。
  73. 只有常成员函数可以操作常对象。
  74. 静态成员函数不能利用 this 指针;静态数据成员要在类体外进行初始化;引用静态数据成员时,要在静态数据成员名前加<类名>和作用域运算符。
  75. 类的非静态成员函数才有 this 指针.
  76. 内联函数是通过编译器来实现的;内联函数不必须通过关键字 inline 来定义。
  77. 将类的一个对象赋予该类的另一个对象时不会调用拷贝构造函数。
  78. 构造函数的功能是对象进行初始化。
  79. 模板声明中的第一个符号总是关键字 template;在模板声明中用 < 和 > 括起来的部分是模板的形参表;类模板可以有数据成员
  80. 静态数据成员不可以在类体内进行初始化
  81. 友元函数破坏了类的封装性和隐藏性。
  82. 表现在计算过程中的被 0 除、内存空间不足、数据的输入输出错误等是程序的运行错误。
  83. C 语言处理错误时可使用 C 信号处理库中的signal函数设置中断信号处理。
  84. 异常对象的捕获和处理是由try - catch结构实现的。
  85. 在已存在的异常到达引起捕获之前又抛出一个新的异常,这会导致对terminate()的调用。
  86. 声明命名空间时,花括号内可以是变量。
  87. 可以被定义为虚函数的是类的非静态成员函数。
  88. 虚函数也可以是成员函数。
  89. 派生类更改了该成员函数的功能,且通过基类指针去访问该函数应考虑把一个成员函数声明为虚函数。
  90. 在程序中最好把基类的析构函数声明为虚函数。
  91. 抽象基类是本类族的公共接口。
  92. 重载的运算符保持其原有的 操作数个数、优先级和结合性不变。
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值