Qs
Q1 命名空间什么作用? Q2 cout输出和printf输出区别在哪?各自的利弊? cin输入时默认遇到空格结束
cout “<<”运算符被重载根据要输出的数据类型进行输出,printf是要手动对输出的内容格式进行操作。
printf 运行时间更短但是麻烦。
Q3 endl作用? 如何避免自动换行?
endl代表的就是换行符号。
Q4 枚举类型适用场景以及方法?
Q5 定义常量的两种方式:宏定义#define和const关键字各有什么区别?
#define identifier value
const type variable = value;
常量通常为全大写 区别:
- const常数同时定义类型和变量,define只定义常数。
- const在编译和运行时起作用,define 在编译预处理时发挥作用*。
- define只是简单字符替换,在预处理阶段就会将identifier=value替换,所以不能够进行调试也不会分配内存,但const可以。
- const不可以重新定义,但是define可通过#undef取消定义。
- ***
define可以防止头文件重复引用。 *** - const在定义时必须赋初值,除使用extern 修饰时可不用赋初值(extern为全局声明关键字)。
Q6 指针“ * ”和引用“&”的区别?
- 指针时一个变量,存储的是内存中存储单元的地址,引用是原变量的别名。
- 可以有const指针。
- 指针可以有多级,但引用只能有一级。
- 指针的值可以为空,但是引用的值必须在定义的时候初始化,不可为空。
- 指针的值初始化之后可以修改,但是引用的值初始化后就不可以修改。
- 指针和引用的自增(++)自减(–)运算意义不一样,指针是对数据的指向进行操作,引用时直接对数据进行操作。
1. #include <iostream>
2. using namespace std;
3. int main (){
4. int a = 10;
5. int &r = a;
6. r++;
7. cout<<r<<endl;
8. int arr[2] = { 27, 84 };
9. int *p = arr;
10. p++;
11. cout<<*p<<endl;
12. return 0;
13. }
输出:
11
84
Q7 static的作用?
- 修饰全局变量时,表明一个全局变量只对定义在同一文件中的函数可见。
- 修饰局部变量时,表明该变量的值不会因为函数终止而丢失。
- 修饰函数时,表明该函数只在同一文件中调用。
Q8 输出缓冲流和非缓冲流分别是什么意思?
缓冲流是输出的流会先存储在缓冲区,直到缓冲区填满或者刷新时才会输出。
Q9 堆(Heap)和栈(Stack)的区别?
- 栈内存时程序自动管理,堆内存在C++中需要通过new和delete进行管理。
- 内联函数?? 为什么建议函数在类外定义??
类的声明和成员函数的定义都是类定义的一部分,在实际开发中,我们通常将类的声明放在头文件中,而将成员函数的定义放在源文件中。
Q9 折构函数 Q10 友元函数和友元类 Q11 内联函数
Ns
N1:修饰符 volatile 告诉编译器不需要优化volatile声明的变量,让程序可以直接从内存中读取变量。对于一般的变量编译器会对变量进行优化,将内存中的变量值放在寄存器中以加快读写效率。
N2 存储类
- register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 ‘&’ 运算符(因为它没有内存位置),介于硬件的限制,也有可能被放在RAM中。
- static 存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。
- extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。
mutable 说明符仅适用于类的对象,这将在本教程的最后进行讲解。它允许对象的成员替代常量。也就是说,mutable 成员可以通过 const 成员函数修改。- 使用 thread_local 说明符声明的变量仅可在它在其上创建的线程上访问。 变量在创建线程时创建,并在销毁线程时销毁。 每个线程都有其自己的变量副本。并且可以与static和extern并用。
N3 Switch语句
switch(expression){
case constant-expression :
statement(s);
break;
case constant-expression :
statement(s);
break;
default :
statement(s);
}
注意:
- switch 语句中的 expression 必须是一个整型或枚举类型,或者是一个 class 类型,
其中 class 有一个单一的转换函数将其转换为整型或枚举类型。 - case 的 constant-expression 必须与 switch 中的变量具有相同的数据类型,且必须是一个常量或字面量。
- [ ] Lambda 函数与表达式
N4 内置的数学函数
库文件(cmath)
- double pow(a, b) a的b次方
- double sqrt(a) a的算数平方根
- int abs(a) 返回整数绝对值
- double fabs(a) 返回浮点数绝对值
- double floor(a) 向下取整
- double ceil(a) 向上取整
N5 随机数(伪)
随机生成器是通过算法根据系统时间的描述来生成的。
库文件: 决定函数伪: srand(times);
N6 setw()和setfill()函数
库文件 (iomanip)
setw() 设定其后面输入内容的宽度,
cout << setw(len) << output1 << endl; 如果 len 比output1的长度大,前面默认用空格填充,否则全部输出。 cout << setfill(*) << setw(len) << output1 << endl;
例子:
cout << setw(10) << "12345" << endl;
cout << setfill('*') << setw(10) << "12345" << endl;
输出:
12345
*****12345
N7 数组和指针的关系
double *p;
double array[10];
p = array;
array代表的事指向&array[0]的指针。 同时 *(p+1) = array[1]
例:
double *p;
double array1[] = {10, 2, 3, 4};
p = array1;
cout << *p << endl;
cout << *(p+1) << endl;
输出:
10
2
N8 struct和class区别
- class的成员属性默认是private,struct默认是public。
class继承默认是private继承,struct默认是public继承。class可以使用模板。
N9 输出特定进制数据
例子:
int a = 90;
cout<<hex<<showbase<<a<<endl;
输出:
0x5a
hex表示以十六进制输出,showbase表示添加十六进制前缀0x。 N10 关于指针和引用
- 指针只能指向内存,如果数据在在寄存器或者硬盘中时就无法获取地址(一些临时变量,表达式的结果或者函数返回值)。
- 常数表达式中不包含变量(其结果为立即数),在编译阶段就会被求值,被“硬编码进指令”,不能寻址。
- GCC下,引用不能指代任何临时数据。
- Visual C++下,引用只能指代位于内存(非代码区)的临时数据。
枚举
举例:
enum type{sign1 , sign2=4, sign3 }name;
cout << sign1 << sign2 << sign3 << endl;
# output:045
# 枚举中数据类型为int,默认起始值为0,其后的值默认依次加1(在没有被赋值的情况下)
变量
变量的名称可以由字母、数字和下划线字符组成,必须以字母或下划线开头
- extern:全局声明变量
- 常量: 布尔值:true、false;
运算符
1. 逻辑运算符
“&&” 逻辑与
“||” 逻辑或
"!" 逻辑非
2. 位运算符
“&” 位与
“|” 位或
“^” 异或
“~” 取反
“<<” 左移位
“>>” 右移位
A = 0011 1100
B = 0000 1101
A&B = 0000 1100
A|B = 0011 1101
A^B = 0011 0001
~A = 1100 0011
A << 2 = 1111 0000
算数和位运算符都可以和“=”结合组成赋值运算符
-=
<<=
&=
^=
- 杂项运算符
1 sieoof() 返回变量的字节大小
2 Condition?X:Y 三目/条件运算符,若Condition为真则值为X,否则为Y。
3 "," 返回系列运算后的最后一个表达式的值。
4 "./->" 成员运算符,访问结构成员时适用“.”,通过指针访问结构成员时适用“->”。
5 强转运算符,可以转换不仅限于常数的运算符。
6 "&" 返回变量的地址
7 "*" 指针运算符,指向指针的地址,
*a 表示将a处的内容取出来。
&b 表示将取出b变量所在的地址。
C++ 指针
1 指针声明
声明指针时,无确切地址可将“NULL”赋值,其被称为空指针,其代表的值在标准库中为0;
2 指针的算数运算
可递减或者递增,变动大小为其数据类型的字节数。
3 指针数组
int *ptr[3] = {&name1, &name2, &name3}; ptr中所有元素都是一个指向int值的指针.
char *names[3] = {"zhang", "Ha", "As"};
以上例子中,除了char数组或者String类型,其他右式的数据类型前需要加取地址符“&”,因为char数组和String类型的变量名就等同于数组和字符串的地址。
数组名代表的数组首位元素的地址
4 多级间接寻址 5 指针传参 6 函数返回指针
1)需要声明函数类型为指针类型,如:int * myFunction()。
2)局部变量的地址不允许返回,除非定义该局部变量为static变量。
类中的this 是 const 指针,它的值是不能被修改的,一切企图修改该指针的操作,如赋值、递增、递减等都是不允许的。只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用。
C++ 引用
引用为已存变量的别名,声明时必须初始化不存在空引用,在初始化后不能修改(地址不可以修改,但是可以修改内容)
例:
int a = 100, aa = 1000;
int &b = a;
cout << b << "-----"<< &b << endl;
b = aa;
cout << b << "-----"<< &b << endl;
输出:
100-----0x61fe04
1000-----0x61fe04
反例:
int &b = a;
&b = aa; # 不允许修改引用。
时间和日期
库文件——(ctime)
输入和输出
库文件为(iostream)
- cin
- cout
- cerr 输出,非缓冲流
- clog 输出,缓冲流
结构体
#include <iostream>
#include <cstring>
using namespace std;
void printBook( struct Books book );
struct Books
{
char title[50];
char author[50];
char subject[100];
int book_id;
};
int main( )
{
Books Book1;
Books Book2;
strcpy( Book1.title, "C++ 教程");
strcpy( Book1.author, "Runoob");
strcpy( Book1.subject, "编程语言");
Book1.book_id = 12345;
strcpy( Book2.title, "CSS 教程");
strcpy( Book2.author, "Runoob");
strcpy( Book2.subject, "前端技术");
Book2.book_id = 12346;
printBook( Book1 );
printBook( Book2 );
return 0;
}
void printBook( struct Books book )
{
cout << "书标题 : " << book.title <<endl;
cout << "书作者 : " << book.author <<endl;
cout << "书类目 : " << book.subject <<endl;
cout << "书 ID : " << book.book_id <<endl;
}
类和对象
1 定义
对象有两种创建方式
1. 栈上创建,形式和普通变量类似,获取地址需要使用“&”,访问成员时使用“.”;
2. 堆上使用new关键字创建,且必须有**指针指向**它,**访问成员时使用“->”**。
例子:
Class Student{
public:
stirng name;
ing age;
};
# 第一种
Student stu;
stu.name = "xiaoming";
# 第二种
Student &stu1 = new Student;
stu1-> name = "xiaoming";
2 成员变量和函数
定义:
- 类不可给成员变量赋值。
- 成员函数可使用域解析符“ :: ”在类外定义,但是必须提前在类中进行声明。
- 成员访问权限未声明的情况下默认为private。
例:
class Student{
public:
char *name;
int age;
float score;
void say();
};
void Student::say(){
cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
成员变量大都以m_开头,这是约定成俗的写法,不是语法规定的内容。 匿名对象无法回收内存,会导致内存泄露
3 构造函数
#include <iostream>
using namespace std;
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
Student(char *name, int age, float score);
void show();
};
Student::Student(char *name, int age, float score){
m_name = name;
m_age = age;
m_score = score;
}
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}
int main(){
Student stu("小明", 15, 92.5f);
stu.show();
Student *pstu = new Student("李华", 16, 96);
pstu -> show();
return 0;
}
构造函数必须是public类型。
构造函数的重载
- 在有多个构造函数的情况下,创建对象时会自动匹配对应实参的函数。
- 用无自定义构造函数时,编译器会自动生成一个空的构造函数。
构造函数初始化列表
成员变量列表赋值顺序和列表数据无关,是由类中的声明顺序决定的。
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
Student(char *name, int age, float score);
void show();
};
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
}
#name(value), name1(value);
this - this 是 const 指针,它的值是不能被修改的,一切企图修改该指针的操作,如赋值、递增、递减等都是不允许的。 - 只有当对象被创建后 this 才有意义,因此不能在 static 成员函数中使用。
static 静态
static静态变量
static 成员变量属于类,不属于某个具体的对象,即使创建多个对象,也只为static成员变量在所有对象之外额外分配一份内存,并为所有实例化的对象共享。
静态成员变量必须初始化,而且只能在类体外进行初始化,默认值为0: type class::name = value;
int Student::name = 10;
static静态函数(什么时候会用到静态函数??)
普通成员函数可以访问所有成员(包括成员变量和成员函数),静态成员函数只能访问静态成员和函数。
普通函数成员在编译时会被隐式的分配一个形参this,并把当前对象的地址赋值给this。所以普通成员函数可以在通过创建对象后进行调用。 编译器不会给静态成员函数分配this指针,所无法调用其他普通的成员函数和变量,只能调用静态成员变量和函数。
#include <iostream>
using namespace std;
class Student{
public:
Student(char *name, int age, float score);
void show();
public:
static int getTotal();
static float getPoints();
private:
static int m_total;
static float m_points;
private:
char *m_name;
int m_age;
float m_score;
};
int Student::m_total = 0;
float Student::m_points = 0.0;
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
m_total++;
m_points += score;
}
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}
int Student::getTotal(){
return m_total;
}
float Student::getPoints(){
return m_points;
}
int main(){
(new Student("小明", 15, 90.6)) -> show();
(new Student("李磊", 16, 80.5)) -> show();
(new Student("张华", 16, 99.0)) -> show();
(new Student("王康", 14, 60.8)) -> show();
int total = Student::getTotal();
float points = Student::getPoints();
cout<<"当前共有"<<total<<"名学生,总成绩是"<<points<<",平均分是"<<points/total<<endl;
return 0;
}
和静态成员变量类似,静态成员函数在声明时要加 static,在定义时不能加 static,静态成员函数一般通过类来调用(不是对象)。
const
const成员变量和函数 成员变量
const成员变量初始化的唯一办法就是初始化列表方法。
class VLA{
private:
const int m_len;
int *m_arr;
public:
VLA(int len);
};
VLA::VLA(int len): m_len(len){
m_arr = new int[len];
}
const常成员函数
const/常成员函数可以使用类中 所有的成员变量,但是不能够改变它们的值(通常会将get函数设置为常成员函数)。
需要在声明和定义的时候在函数头的结尾加上const关键字。
class Student{
public:
Student(char *name, int age, float score);
void show();
char *getname() const;
int getage() const;
float getscore() const;
private:
char *m_name;
int m_age;
float m_score;
};
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}
char * Student::getname() const{
return m_name;
}
int Student::getage() const{
return m_age;
}
float Student::getscore() const{
return m_score;
}
const对象
同静态static一样,const也只能调用同类的const成员(const成员变量和const成员函数)
字符串
C风格字符串
本质上是以“\0”字符结束的一位字符数组。
函数:
1 strcpy(s1, s2); 复制字符串 s2 到字符串 s1,并返回复制的内容(返回的对象是前者s1)
2 strcat(s1, s2); 接字符串 s2 到字符串 s1 的末尾,或者直接用“+”号。
3 strlen(s1); 返回字符串的长度。
4 strcmp(s1, s2); 若s1=s2返回0, s1>s2返回值大于0,s1<s2返回值小于0(两个字符串自左向右逐个字符相比(按ASCII值大小相比较),
只能比较字符串常量、数组,数字等其他形式的参不能比较).
5 strchr(s1, ch); 返回一个指针,指向字符串 s1 中字符 ch 的第一次出现的位置。
6 strstr(s1, s2);返回一个指针,指向字符串 s1 中字符串 s2 的第一次出现的位置。
C++中的String类型操作方法和上述相同。
String类型字符串
- 与C风格字符串(char *str)和字符数组(char str[n])不同,string结尾无“\0”。
- 获取字符串长度:str.length()。
- string向C风格const类型字符串转换(c_str()):str.c_str(),返回的事const指针。
- 支持下标访问。
1 字符串拼接
String可和string、字符、c风格字符串和字符数组进行拼接。
2 插入字符串
insert函数在指定位置插入指定字符串、c风格字符串、字符数组(字符除外)。
str.insert (size_t pos, const string& str);
3 删除字符串
erase删除字符串。
str.erase(start_pos, len); # (起始位置, 删除长度),无删除长度默认删除到最后。
4 提取字符串
substr()
例:
string str = "012345";
string s;
s = str.substr(0, 4);
输出:
01234
5 查找字符串
- find():str.find(str1/s(char *), pos), 第一个参数可以是string或者C风格字符串,第二个参数为开始查找的位置(默认从下标为0开始),返回第一次出现字符串的位置(查找失败则返回一个无穷大的值4294967295)。
- rfind():大体同上(这里第二个参数为截止位置)。
- find_first_of() :str.find_first_of(str1) 返回两个字符串第一次出现相同字符的位置,查找失败则返回无穷大值。
继承
单继承:
class <子类名>: <继承类型> <父类名>{}
多继承:
class <子类名>: <继承类型> <父类名>, <继承类型> <父类名>{}
子类可以继承父类中除了以下几种方法:
- 父类的构造函数、析构函数和拷贝构造函数。
- 父类的重载运算符。
- 父类的友元函数。
继承类型
- public:拥有父类的所有等级权限。
- protected:父类的public会变成子类的protected。
- private:父类的所有权限会变成子类的private。
多态
多态的功能:
- 通过父类指针对所有子类(包括直接子类和间接子类)的成员变量和成员函数进行“全方位”的访问。
- 在父类的基础上,让多个子类分别对同一个成员函数有不同的表现形式。
实现方法: 在父类的成员函数类型前加上 “virtual”(虚函数)。
virtual void display();
纯虚函数
virtual 返回值类型 函数名 (函数参数) = 0;
尾部含有“” =0“” 的虚函数为纯虚函数(其他函数不可以),包含纯虚函数的类称为抽象类,并且无法被实例化。
多态的成员函数一般为public,成员变量一般为**protected**。
不仅是指针,引用也可以实现多态,由于其不可以更改引用所以灵活性较差。
重载
重载声明指一个与之前在同作用域内声明的函数或者方法具有相同名称的声明,但是它们的参数列表(参数的个数、类型和顺序)和实现不同(返回类型不能当做判断)。 重载运算符 C++ 内置的运算符大部分都可以被重定义或重载,
重载函数
函数模板的重载 对于一些混合数据类型,如int、double和数组等,模使用过程中会产生一些错误。
文件和流
标准库:(fstream) 三种数据类型:
- ofstream 输出文件流,创建文件并写入信息。
- ifstream 输入文件流,从文件读取信息。
- fstream 文件流同时有of和if两种功能。
操作模式:
- ios::app 追加模式,将所有写入都追加到文件末尾。
- ios::ate 文件打开后定位到末尾
- ios::in 打开文件进行读取
- ios::out 打开文件用于写入(该模式打开文件会将内容清空)
- ios::trunc 若文件已存在,其内容在打开之前将被截断,把文件长度设为0.
打开和关闭文件:
void open(const char *filename, ios::openmode mode);
void close();
异常处理
头文件(exception) 语法:
try{
}catch(exceptionType variable){
}
例:
try{
}catch(exception &e){
}
在异常变量处使用引用的原因是为了提高效率,如果不适用,就会经历一次对象拷贝(掉出拷贝构造函数)的过程。
如果在try中检测到throw出的异常后,程序会立即从当前位置跳转到catch语句中。
**exceptionType:**指明当前的catch可以处理的异常类型。异常类型可以是 int、char、float、bool 等基本类型,也可以是指针、数组、字符串、结构体、类等聚合类型。C++ 语言本身以及标准库中的函数抛出的异常,都是 exception 类或其子类的异常。 variable: 用来接收异常信息。
N14 函数实参和形参的自动转换
- 算法转换:如int转float,char转int,double转int。
- 向上转型:派生类向基类的转换。
- const转换:将非const;类型转换成const类型。
- **
数组或者函数指针转换:若函数形参不是引用类型,那么数组名会转换成数组指针,函数名也会转换成函数指针。 ** - 用户自定义的类型转换。
catch在转换实参和形参转换过程中,唯二进行的转换为向上转型和数组或函数指针转换。
异常规范 1 虚函数的异常规范: 派生类虚函数的异常规范必须与基类虚函数的异常规范一样严格,或者更严格。 2 异常规范与函数定义和声明: 异常规范在函数声明和函数定义中必须同时指明,并且要严格保持一致,不能更加严格或者更加宽松。
自定义异常
#include <iostream>
#include <exception>
using namespace std;
struct MyException : public exception
{
const char * what () const throw ()
{
return "C++ Exception";
}
};
int main()
{
try
{
throw MyException();
}
catch(MyException& e)
{
std::cout << "MyException caught" << std::endl;
std::cout << e.what() << std::endl;
}
catch(std::exception& e)
{
}
}
exception类
动态内存
- 栈:所有在函数内部声明的变量都占用栈的内存。
- 堆:程序中未使用的内存,在程序运行时用于动态分配。
new和delete运算符 new和malloc相比在于,new不仅仅是分配内存还创建了对象。
动态二维数组分配:
int **array
array = new int *[m];
for( int i=0; i<m; i++ )
{
array[i] = new int [n] ;
}
for( int i=0; i<m; i++ )
{
delete [] array[i];
}
delete [] array;
命名空间
命名空间是作为附加信息用来区分不同库中相同名称的函数、类、变量等,从而定义上下文。 定义:
namespace namespace_name {
}
调用:
name::code;
命名空间可以定义在几个不同的部分中,其可由几个单独定义的部分组成,其各个组成部分可以分散在多个文件夹中(怎么用?)
模板
类型的参数化: C++中,数据的类型可以通过参数进行传递,在函数定义时可以不指名具体的数据类型,当函数发生调用时,编译器可以根据传入的实参自动判断数据类型。 Value和Type在C++中都可以被参数化。
函数模板 定义:建立一个通用函数,其数据类型(返回值类型、形参类型、局部变量类型)可以不具体指定,使用虚拟的类型进行代替(标识符),在函数调用时根据传入的实参推出实际的类型。
形式:
templates <typename type1, type2...> return-type func-name(para list){
}
#include <iostream>
using namespace std;
# 交换数据值
template<typename T> void Swap(T &a, T &b){
T temp = a;
a = b;
b = temp;
}
int main(){
int n1 = 100, n2 = 200;
Swap(n1, n2);
cout << n1 << "------" << n2 <<endl;
}
类模板
语法:
template<typename type1, type2...> class class-name{
};
template<typename T1, typenmae T2>
class Point{
private:
T1 m_x;
T2 m_y;
public:
Point(T1 x, T2 y):m_x(x), m_y(y){}
public:
T1 getX() const;
void setX(T1 x);
T2 getY() const;
void setY(T2 y);
};
}
template<typename T1, typename T2>
T1 Point<T1, T2>::getX() const {
return m_x;
}
template<typename T1, typename T2>
void Point<T1, T2>::setX(T1 x){
m_x = x
}
使用类模板创建对象
在类模板实例化时,必须显式地指明数据类型。 使用对象指针方式时,赋值号“=”两端必须指明具体的数据类型,并保持一致。
方式一(对象变量):
Point<int, int> p1(10, 20);
Point<int, float> p2(10, 12.3);
Point<float, char*> p3(12.3, "你好小七");
方式二(对象指针):
Point<float, float> *p1 = new Point<float, float>(10.6, 109.3);
Point<char*, char*> *p = new Point<char*, char*>("东经180度", "北纬210度");
类模板实现可变长数组
函数模板的实参推断
上面提到过,对于普通函数,函数调用时会对实参的类型进行适当的转换,以适应形参的类型。 但对于函数模板,类型转换仅限于const转换和数组或函数指针转换,并且当函数形参是引用类型时,数组不会转换成指针。
为函数模板显示地指明实参:
template<typename T1, typename T2> void fun(T1 a){
T2 b;
}
fun<int, int>(20);
显式指明的模板实参会按照从左到右的顺序与对应的模板参数匹配(最后一个可以省略)。
显示具体化 1 函数模板
2 类模板
预处理器
#define 预处理
参数宏
#include <iostream>
using namespace std;
#define MIN(a,b) (a<b ? a : b)
int main ()
{
int i, j;
i = 100;
j = 30;
cout <<"较小的值为:" << MIN(i, j) << endl;
return 0;
}
条件编译 有选择地对部分程序源代码进行编译。
#include <iostream>
using namespace std;
#define DEBUG
#define MIN(a,b) (((a)<(b)) ? a : b)
int main ()
{
int i, j;
i = 100;
j = 30;
#ifdef DEBUG
cerr <<"Trace: Inside main function" << endl;
#endif
#if 0
cout << MKSTR(HELLO C++) << endl;
#endif
cout <<"The minimum is " << MIN(i, j) << endl;
#ifdef DEBUG
cerr <<"Trace: Coming out of main function" << endl;
#endif
return 0;
}
输出:
Trace: Inside main function
The minimum is 30
Trace: Coming out of main function
#和##运算符 “#”会把replacement-txt令牌转换成引号引起来的字符串。 "##"用于连接两个令牌
#include <iostream>
using namespace std;
#define MKSTR(x) #x
#define concat(a, b) a ## b
int main()
{
int xy = 100;
cout << MKSTR(dingdingdang) << endl;
cout << concat(x, y) << endl;
return 0;
}
输出:
dingdingdang
100
预定义宏
- LINE : 其所在语句的行数。
- FILE:当前文件所在的路径。
- DATE:源文件转换为目标代码的日期。
- TIME:程序被编译的日期,形式为“hour:,minute:second”
信号处理
定义在C++头文件“<csingal>”中,可以被程序捕获并采取适当动作的信号。
- SIGABRT:程序的异常终止,如调用 abort。
- SIGFPE:错误的算术运算,比如除以零或导致溢出的操作。
- SIGILL:检测非法指令。
- SIGINT:程序终止(interrupt)信号。
- SIGSEGV: 非法访问内存。
- SIGTERM:发送到程序的终止请求。
捕获信号:
signal(registered signal, signal handler)
其中registered代表了捕获到的信号编号(为整数),signal是指向信号处理函数的指针。
发送信号:
int raise (signal sig);
多线程
STL
|