西电C++期末考点整理

Chapter 4 Types

1、类型

  • 浮点类型:float, double, long double

浮点类型后加f或者F为float,加l或者L为long double,什么也不加默认是double类型
在运算符重载,函数重载这两个点需要注意类型的问题。

  • void类型

值集:空集

void* :不限制

2、声明

定义声明+非定义声明

非定义声明:先承认再核实

在这里插入图片描述

int x;	//全局量(x1)

void f(int x){
	//int x;	//局部变量冲突定义
	x = 1;	//x2 = 1
	{
		int x;	//局部量(x3)
		x =2; //x3 = 2
		::x = 3;	//x1 = 3
	}
}

::x全局量

3、枚举类型

枚举值集中的每一个值都是一个已命名的整数常量,这个名字是枚举类型的字面值:

enum keyword{ASM, AUTO, BREAK};//不指定值,从0开始递增
enum summer_month{Jun = 6, Jul = 7, Aug = 8};//指定值,注意值不能重复

Chapter 5 Pointers and Array

1、指针

  • 值集:合法的地址集合子集
//1.定义声明
char* pc;	//pc:指向char值的指针
int* pi;	//pi:指向int值的指针
char** ppc;	//指向“指向char值的指针”的指针
/******************************/
/******************************/
int* ap[15];	//ap:由15个指向int值的指针组成的数组
/******************************/
/******************************/
//定义声明
int (*fp)(char*);	//定义函数指针

//非定义声明
int* f(char*);

函数指针的定义:

#include<iostream>

using namespace std;

void test(char* p){
	cout<<(*p)<<endl;
}

void (*ptr)(char* p) = test;
void (*point)(char* p);

int main()
{
	char a = 'C';
	point = test;
	
	ptr(&a);
	(*ptr)(&a);
	point(&a);
	return 0;
 } 

取地址和解引用互为逆操作:&(address of )与*(dereferencing)

2、数组

数组的定义:

数组定义的两种写法

float v[3];	//float[3] v;
char* a[32];	//(char*)[32] a;

int d2[10][20];	//(int[10])[20] d2;

数组大小可以不写:

int v1[] = {1,2,3,4,5};	//int[5] v1;
char v2[] = {'a','b','c',0};	//char[4] v2;

int i,j,k;
int* v3[] = {&i, &j, &k, 0};	//int*[4] v3;

如果给出了size,那么在初始化的时候,元素的个数不能大于size,但是可以小于size。C++自动地给未给出初值的元素赋0

int v1[] = {1,2,3,4,5};	//int[5] v1;
char v2[2] = {'a','b','c',0};	//error!!!

int i,j,k;
int* v3[6] = {&i, &j, &k, 0};	//int*[6] v3 = {&i, &j, &k, 0, 0, 0, 0, 0};

可以将一个常量字符串由一个指针char* p指向,但是不允许修改其中的任何元素,因为该指针指向的是一个const字符数组。(即下面将要说明的:变量的指针会有意无意的修改常量的内容,所以不允许用一个变量的指针指向一个常量,这里比较特殊)

在这里插入图片描述

//"this is a string"的类型是const 

掌握下面的各个写法最终获得的结果是什么:

int v[] = {1,2,3,4};	//int[4]
int* p1 = v;	//隐式转换为int* p1 = &v[0]
int* p2 = &v[0];
int* p3 = &v[4];//允许指针指向数组外的元素,但后果自负

区别*p++++p*之间的区别

void f()
{
	int v1[10];
	int v2[10];
	
	int i1 = &v[5]-&v1[3];// i1 = 2
	int i2 = &v[5]-&v2[3];// result undefined
}

3、数值常量和指针常量

数值常量:const <类型名><常量名> = <初值>

常量指针的声明:数据类型 const * 指针变量或者 const 数据类型 *指针变量。

对于类型是T*时,这个指针不能指向别的内容

在这里插入图片描述

指针常量:<指针类型> const <常量名> = <初值>

这里不能修改的是指针所指向的地址,而地址对应的内容可以修改。

指针常量和常量指针的例子:

/*指针常量的例子*/ 
int a,b; 
int * const p; 
p = &a;//正确 
p = &b;//错误 
*p = 20;//正确 
/*常量指针的例子*/ 
int a,b; 
int const *p; 
p = &a;//正确 
p = &b;//正确 
 
*p = 20;//错误 

加了[]和解引用*是一样的效果取的都是内容。

区别指针常量和常量指针:

只要是T*开头的就是指针常量,指针常量的地址不能改变,但是地址中的内容可以改变。

除了T*开头的和指针有关的常量,都是常量指针,指针指向的是一个常量,指针的地址可以改变,但是不能通过指针去修改该地址的内容。

变量的变化不会改变指针常量的值,而指针变量的变化会有意或无意修改常量的值,所以不能用一个变量指针去指向一个常量,因为指针可能会修改这个常量的值:

例:
void f4()
{
    int a = 1;
    const int c = 2;
    const int* p1 = &c; // ok
    const int* p2 = &a; // ok
    int* p3 = &c; // error: initialization of int* with const int*
    *p3 = 7; // try to change the value of c
}

修改方法:const int* p3 = &c;,去掉第9行。

4、引用

The notation X& means reference to X;

void g()
{
    int ii = 0;
    int& rr = ii; // rr是ii的引用
    rr++; // 等价于:ii++;
    int* pp = &rr; // pp = = &ii; *pp = = ii;
}

5、结构

C++中的 struct 和 class 基本是通用的,唯有几个细节不同:

  • 使用 class 时,类中的成员默认都是 private 属性的;而使用 struct 时,结构体中的成员默认都是 public 属性的。
  • class 继承默认是 private 继承,而 struct 继承默认是 public 继承。
  • class 可以使用模板,而 struct 不能。

结构中的类型成员不能是它自身。

Chapter 7 Functions and Declarations

1.变量声明

#include<iostream>
using namespace std;

void f(int a) 
{
    while (a--) {
        static int n = 0;
        int x = 0;
        cout<<"n=="<<n++<<", x== "<<x++<<'\n';
	}
}

int main ()
{
    f(3);
    f(2);
    return 0;
}

运行结果如下:

n==0, x== 0
n==1, x== 0
n==2, x== 0
n==3, x== 0
n==4, x== 0

可以看出static变量的声明语句只会被运行一次,但是后续的更改是会不断进行的,即变量的生命期得到延长。

局部变量每次进入作用域都会被初始化一次。

2.参数传递

区分清楚值传递和引用传递;引用传递传递的对象一定是能够取左值的对象。int& ref = 2这样的定义声明时错误的。

在这里插入图片描述

在这里插入图片描述

在一个返回值类型为 void 的函数中,可以出现没有返 回值的 return 语句,也可以出现调用另一个返回值类型为void 的函数的 return 语句

void g(int* p);
void h(int* p)
{
    if (*p > 0)
   		return;
    return g(p);
}

3.过载函数名

函数名过载,是指它们在同一区域内:

  • 相同的函数名
  • 不同的参数表(参数数目不同,或类型不同,或顺序不同)。

但是,仅仅是返回值类型不同的两 个函数,编译程序不是按过载函数对待,而是按重复定义了函数进行出错处理。

3.1 二义性

#include<iostream>

using namespace std;

void print(double);
void print(long);

void f()
{
	print(1L); // match print(long) 
	print(1.0); // match print(double)
	print(1); // error!
}

int main()
{
	return 0;
}

int是能够隐式转换为long和double的,所以造成了二义性

float可以隐式转换为int

  • 不在一个作用域里不会发生函数重载
void f(int);
void g()
{void f(double);
    f(1); //call f(double)
}
int pow(int, int);
double pow(double, double);
void g( ) {
	double d = pow(2.0, 2); // error!
}
  • 函数缺省值

注意点:Default Arguments 必须位于参数表的后部,而且中间没有插入非 Default Arguments。

int f(int, int = 0, char* = 0); //ok
int g(int = 0, int = 0, char*); //error
int h(int = 0,int, char* = 0); //error

下面的写法为语法错误,编译器不知道是缺省还是*=,要加一个空格区分

int nasty(char*=0); // syntax error

函数的缺省值在一个作用域中不能重复或者改变,会造成错误。

void f(int x = 7);
void f(int 7); // error: repeat
void f(int x = 8); // error: modifier
void g()
{
    void f(int x = 9); // ok: hides the outer one
    //…
}
  • 使用…代表可能有的更多的参数

这类函数至少应当有一个确定的形参,不能是: T f( … )

#include<iostream>
#include <stdarg.h>

using namespace std;

void test(char c, ...)
{
	va_list ap;
	va_start(ap, c);
	while(1){
		int i = va_arg(ap, int);
		cout<<i<<endl;
		if(i==-1){
			break;
		}
	}
}

int main()
{
	test(1,2,3,4,5,6,7,8,-1);
	return 0;
}

4.函数指针

函数跳转表的应用:

typedef int (*FP)(char*); // 函数指针类型 FP
int f(char* p);
int g(char* p);
int h(char* p);
const int invalid_fp = -1;
// 利用函数指针构成这一类函数的跳转表
const int table_size = 3;
FP jump_talbe[ ] = { &f, &g, &h };
int driver(int id, char* arg)
{
    if (id >= 0 && id < table_size)
    return jump_table[id](arg);
    return invalid_fp;
}

5.宏

#define MAX(a, b) (a > b) ? a : b
#define MIN(a, b) (a < b) ? a : b
void f()
{
    int m = MAX(1, 100); // m = (1 > 100) ? 1 : 100;
    double n = MIN(10.123, 6); // n = (10.123 < 6) ? 10.123 : 6;
}

Chapter 9 Source File and Programs

  • 不同翻译单元中的同以全局名字,定义声明和非定义声明有相同的类型。
  • 定义声明只有一个,其他为extern声明

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2IZdGHad-1623918665309)(C:/Users/%E5%AD%99%E8%95%B4%E7%90%A6/AppData/Roaming/Typora/typora-user-images/image-20210616195155383.png)]

在这里插入图片描述

  • 不同翻译单元中能出现相同名字的自定义类型,但是前提是元素得一样,完全一样!!连名字都一样!

在这里插入图片描述

不能在.h文件里面出现的:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5yrv0L9B-1623918665312)(C:/Users/%E5%AD%99%E8%95%B4%E7%90%A6/AppData/Roaming/Typora/typora-user-images/image-20210616200344433.png)]

Chapter 10 Class

1.构造函数

构造函数调用的形式:

A a;//调用默认构造函数
A a(1,2);//隐式调用
A a = A(1,2);//显式调用
A* a = new A(1,2);

当数据成员含有常量类型或者引用类型,那么编译器不会自动提供默认构造函数,除非程序员主动提供构造函数。

#include<stdio.h>
#include<string.h>
#include<iostream>

using namespace std;

class Date {
private:
	const int a; // const member
	const int& r; // const and reference member
};

int main()
{
	Date today;// error: no default constructor for Date
	retrun 0;
}

2、静态成员函数

只对静态数据成员进行操作的函数:静态成员函数

3、析构函数

desconstructor不允许有形参,因此不过载

重复调用一个对象的析构函数可能引起运行时错误

int main()
{
    Table* p = new Table;
    Table* q = new Table;
    delete p;
    delete p; // 可能引起运行时错误
} // 自动调用delete q

Chapter 11 Operator Overloading

1.运算符重载

过载定义操作符 = 、[ ]、( )、->的必须是非静态成员函数,以 保证其第一操作数一定是左值(lvalue);

过载定义操作符时至少有一个操作数是自定义类型的:不能全部都是基本数据类型

  • 新类型到基本数据类型的转换

这是单参数构造函数无法完成的,需要重载强制类型转换的运算符,如下:

#include <iostream>

using namespace std;

class complex{
public:
	double re;
public:
	complex(double re = 0):re(re){
		cout<<"constructor~"<<endl;
	}
	operator double(){
		return re;
	} 
	~complex(){
		cout<<"desconstructor~"<<endl;
	}
};

int main()
{
	complex c(4);
	
	cout<<c.re<<endl;
	cout<<double(c)<<endl;
	cout<<"--------"<<endl;
	
	//delete c2;
	return 0;
}

由于返回值类型可知,所以强制类型转化不需要写返回值类型,同时参数表为空,因为是this本身。

2.友元函数

友元函数和成员函数不要同时使用,会产生二义性。

3.explicit

在这里插入图片描述

在这里插入图片描述

  • 拷贝赋值运算符合拷贝构造函数

Chapter 12 Derived Class

一旦一个成员函数在某个类中被定义成虚拟函数,那么在这个类中必须定义这个虚拟函数的实现代码(纯虚拟函数除外)

纯虚函数的定义方法:... function() = 0

class Shape { // abstract class
public:
    virtual void rotate(int) = 0; // pure virtual function
    virtual void draw() = 0; // pure virtual function
    virtual void is_closed() = 0; // pure virtual function
    // …
};

注意抽象类不能创建对象!

Shape s; // 错误:不能创建抽象类的对象
Shape *sptr; // 正确

C++的抽象基类常常用来定义共享接口。

如果纯抽象类的子类保持着纯虚函数,没有重写,那么这个派生类仍是抽象类。

#include<stdio.h>
#include<iostream>

using namespace std;

class Date {
protected:
	int year, month, day;
public:
	Date( int y, int m, int d){
		year = y, month = m, day = d;
	}
	virtual void print() {
		cout << year << '-' << month<< '-' << day << endl;
	}
};

class ShortDate : public Date {
public:
	ShortDate(int y, int m, int d) : Date(y, m, d) {}
	void print(){
		cout << day << '-' << month << '-' << year << endl;
	}
};

void printDate(Date* dp) {
	dp->print();
}

class MediumDate : public Date {
public:
	MediumDate(int y, int m, int d) : Date(y, m, d) {}
	void print(){
        switch ( month ){
            case 1: cout << "Jan."; break;
            case 2: cout << "Feb."; break;
            case 3: cout << "Mar."; break;
            case 4: cout << "Apr."; break;
            case 5: cout << "May."; break;
            case 6: cout << "Jun."; break;
            case 7: cout << "Jul."; break;
            case 8: cout << "Aug."; break;
            case 9: cout << "Sep."; break;
            case 10: cout << "Oct."; break;
            case 11: cout << "Nov."; break;
            case 12: cout << "Dec."; break;
            default: cout << "Err."; break;
        }
		cout << " " << day << ", " << year << endl;
	}
};

class LongDate : public Date {
public:
	LongDate(int y, int m, int d) : Date(y, m, d) {}
	void print(){
		switch ( month ){
		case 1: cout << "January"; break;
		case 2: cout << "February"; break;
		case 3: cout << "March"; break;
		case 4: cout << "April"; break;
		case 5: cout << "May"; break;
		case 6: cout << "June"; break;
		case 7: cout << "July"; break;
		case 8: cout << "August"; break;
		case 9: cout << "September"; break;
		case 10: cout << "October"; break;
		case 11: cout << "November"; break;
		case 12: cout << "December"; break;
		default: cout << "Error"; break;
		}
		cout << " " << day << ", " << year << endl;
	}
};

int main( )
{
	Date d (2006, 6, 30);
	ShortDate sd (2006, 5, 31);
	MediumDate md (2006, 9, 21);
	LongDate ld (2006, 9, 21);
	printDate(&d); // Display: 2006-6-30
	printDate(&sd); // Display: 31-5-2006
	printDate(&md); // Display: Sep. 21, 2006
	printDate(&ld); // Display: September 21, 2006
	return 0; 
}

提供的接口不仅仅是成员函数,全局函数也可以方便做接口。

Chapter 13 Templates

1.类模板

将类型作为参数的抽象结构称为类属(generic)

类模板以关键字template开始,后跟参数模板列表:参数模板列表使用typename和class效果相同

#include<stdio.h>

using namespace std;

template<class C> class String{
	struct Srep;
	Srep* rep;
	public:
	String();
	String(const C*);
	String(const String&);
	C read(int i)const;
	// ...
};

template<class C> struct String<C>::Srep {//如何定义 
	C* s;
	int sz;
	int n;
	// ... 
};

int main()
{
	return 0;
} 

模板的参数列表中可以声明多个形参:

先声明的可以用来定义统一参数表中的其他参数

template<typename T, T def_val> class count{
	//...
}

参数列表中的int类型必须是一个常量:

template<class T, int i> class Buffer{
	T v[i];
	int size;
public:
	Buffer():size(i){}
	//
}

void f(int i){
	Buffer<int,i> bx;//错误,必须是常量
}

2.函数模板

函数模板写法:

#include<stdio.h>
#include<vector>
using namespace std;

template<class T> void sort(vector<T> &);

void f(vector<int>& vi, vector<double>& vd){
	sort(vi);
	sort(vd);
}

int main()
{
	return 0;
} 
 
template <class T> void sort(vector<T>& v)
{
	int n = v.size();
	for (int gap = n/2; 0 < gap; gap /= 2){
		for (int i = gap; i < n; i++){
			for (int j = i-gap; 0 <= j; j -= gap){
				if (v[j+gap] < v[j]){
					T temp = v[j];
					v[j] = v[j+gap];
					v[j+gap] = temp;
				}
			}
		}
	}
}

函数模板可重载:

template <class T>T max(T x, T y)
{ 
	return(x > y) ? x : y; 
}
template <class T> T max(T x, T y, T z)
{ 
	T t;
	t = (x > y) ? x : y;
	return (t > z) ? t : z;
}

类模板的继承:

template<class T> class Vec : public Vector<T> {
	// ...
};
template<class T> class Teacher : public Person {
	// ...
};

模板实现的队列:

#include<stdio.h>
#include<iostream>

using namespace std;

template<typename T, int max_size> class Queue
{
private:
	T arr[max_size];
	int curr_num;
public:
	Queue(){
		curr_num = 0;
	}
	bool empty(){
		return curr_num<=0;
	}
	bool full(){
		return curr_num>=max_size;
	}
	void push(const T& v){
		if(full()){
			cout<<"queue is full!"<<endl;
			return;
		}
		arr[curr_num++] = v;
	}
	T pop(){
		T dummy;
		if(empty()){
			cout<<"queue if empty!"<<endl;
			return dummy;
		}
		T v = arr[0];
		for(int i = 0; i<curr_num; i++){
			arr[i] = arr[i+1]; 
		}
		curr_num--;
		return v;
	}
	
};

int main()
{
	const int max_size = 5;
	Queue<int, max_size> myQ;
	
	//cout<<myQ.empty()<<endl;
	//cout<<myQ.full()<<endl;
	
	for(int i = 0; i < max_size+1; i++){
		myQ.push(i);
	}
	while(!myQ.empty()){
		cout<<myQ.pop()<<endl;
	}
	return 0;
}

Chapter 14 Exception Handling

#include<stdio.h>
#include<iostream>
#include <limits>

using namespace std;

struct Range_error{
	int i;
	Range_error(int ii):i(ii){
	}
}; 

char to_char(int i){
	if (i < numeric_limits<char>::min ()||i > numeric_limits<char>::max ())
		throw Range_error (i) ;  //出现了异常,报告之,若“有人catch”则跳出, 否则立刻终止运行
	return i;
}

int main()
{
	try{
		to_char(555555555);
	}
	catch(Range_error e){
		cout<<"range_error"<<endl;
	}
	return 0;
}

捕获任意异常catch(...)一定要放在catch句组的末尾

下面的写法是错误的!!!

void g() {
    try { // … }
    catch (){
    	// handle every exception
    }
    catch (std::exception& e) {
    	// handle any standard library exception
    }
    catch (std::bad_cast) {
    	// handle dynamic_castfailure
    }
}

nt i = 0; i < max_size+1; i++){
myQ.push(i);
}
while(!myQ.empty()){
cout<<myQ.pop()<<endl;
}
return 0;
}


## Chapter 14 Exception Handling



```cpp
#include<stdio.h>
#include<iostream>
#include <limits>

using namespace std;

struct Range_error{
	int i;
	Range_error(int ii):i(ii){
	}
}; 

char to_char(int i){
	if (i < numeric_limits<char>::min ()||i > numeric_limits<char>::max ())
		throw Range_error (i) ;  //出现了异常,报告之,若“有人catch”则跳出, 否则立刻终止运行
	return i;
}

int main()
{
	try{
		to_char(555555555);
	}
	catch(Range_error e){
		cout<<"range_error"<<endl;
	}
	return 0;
}

捕获任意异常catch(...)一定要放在catch句组的末尾

下面的写法是错误的!!!

void g() {
    try { // … }
    catch (){
    	// handle every exception
    }
    catch (std::exception& e) {
    	// handle any standard library exception
    }
    catch (std::bad_cast) {
    	// handle dynamic_castfailure
    }
}
  • 11
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Blanche117

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值