(一)简介
1.C++的编程特点:
(1)结构化编程:强调实现算法的设计,自顶向下的设计原则;
(2)面向对象编程:由类,对象等组成;强调数据的设计,自底向上的设计原则;
(3)泛型编程:由模板组成;强调创建适用于各种数据类型的代码模块;
2.C++程序源文件扩展名常用.cpp,头文件扩展名常用.h;
3.C++的注释方式有 / / 跟 /*...*/ 两种;
4.C++语句以分号结尾;
5.简单的hello world程序
#include<iostream>
using namespace std;
int main()
{
cout<<"hello world"<<endl;
return 0;
}
(1)预处理:C++的预处理阶段,就是读取C++源程序,对其中的伪指令(以#开头的指令)和特殊符号进行初步的转换,产生新的源代码提供给编译器;预处理过程还会删除程序中的注释和多余的空白字符;C++的四种主要预处理包括:头文件包含、条件编译、宏定义、特殊符号替换;
1)头文件包含:
a)头文件包含处理是指在一个源文件中,通过"#include"命令将另一个源文件的内容全部包含在此文件中;在源文件编译时,连同被包含进来的文件一同编译,生成目标目标文件;
b)系统自带头文件中,C++头文件没有扩展名,C头文件扩展名为.h;以C头文件转换为C++头文件后,文件被重命名,去掉后缀.h并加上前缀c;
c)在包含头文件时,如果文件名包含在尖括号中,则C++编译器将在存储标准头文件的主机系统的文件系统中查找;但如果文件名包含在双引号中,则编译器将首先查找当前的工作目录或源代码目录(或其他目录,这取决于编译器);如果没有在那里找到头文件,则将在标准位置查找;
d)头文件中经常包含的内容:函数原型,使用#define或const定义的符号常量,结构声明,类声明,模板声明,内联函数;
e)头文件定义:(注意格式:下划线,头文件名大写)
#ifndef __NAME__
#define __NAME__
....
#endif
2)条件编译:
a)条件编译指令将决定那些代码被编译,而哪些是不被编译的;可以根据表达式的值或者某个特定的宏是否被定义来确定编译条件;
b)条件指示符的最主要目的是防止头文件的重复包含和编译;
c)常见指令:
3)宏定义:
a)宏定义又称为宏代换、宏替换,简称“宏”;
b)格式:#define 标识符 字符串 (字符串可以是常数、表达式、格式串等)
c)宏定义写在函数的花括号外边,作用域为其后的程序,通常在文件的最开头;
d)可以用#undef命令终止宏定义的作用域 ;
e)宏名一般用大写 ;
4)特殊符号替换:
a)预编译程序可以识别一些特殊的符号;预编译程序对于在源程序中出现的这些串将用合适的值进行替换;
b)常见特殊符号:(注意是双下划线)
_ _FILE _ _ : 包含当前程序文件名的字符串
_ _DATE _ _ :包含当前日期的字符串
_ _TIME _ _ : 包含当前时间的字符串
(2)命名空间
1)名称空间编译指令是一项C++特性,变量,函数,类是C++编译器的标准组件,放置在名称空间std中,因此C++头文件中的变量,函数,类等也放在std中;
2)using namespace std / using std::cout
PS:using语句要用分号结尾;
(3)main()函数
1)C++语法要求main函数的定义以int main()开始;通常main()被启动代码调用,启动代码是编译器添加到程序中的,是程序和操作系统之间的桥梁,实际上,该函数头描述的是main()和操作系统之间的接口;
2) int main(int argc, char* argv[]) ;其中argc表示命令行中用户输入参数个数,argv表示命令行中用户输入参数的字符串数组;
(4)程序的运行过程:
PS:windows平台上常用编译器MSVC++(可用系统自定义宏定义_MSC_VER查看编译器版本号),类unix平台上常用编译器g++;
(二)基本语法
1.数据类型
(1)整型
1)C++的基本整型分别是char,short,int,long,long long;其中每种类型都包括有符号版本和无符号版本(关键字unsigned);
2)char类型是专为存储字符(如字母和数字等)而设计的整型;在计算机中,char是以整数的形式存在的,因此可以进行一些整数的操作运算,但是在输入与显示时,是cin与cout完成的转换工作,以字符的形式存在;
3)整型数据所占字节数与系统的实现有关,不同的机器,系统跟编译器,实现不同,可以用sizeof进行查看;
4)64位机器,64位windows系统,x64编译平台上,char为一个字节,short为2个字节,int与long为4个字节,long long为8个字节;
(2)浮点数
1)浮点数能够表示小数值,非常大和非常小的值;
2)C++有两种书写浮点数的方式:常用的标准小数点表示法和E表示法;
3)浮点类型有3种:float,double,long double;
4)64位机器,64位windows系统,x64编译平台上,float为4个字节,double为8个字节,long double为8个字节;
(3)数组
1)声明数组的通用格式:typename arrayname[arraysize] = {};
2)C++数组从0开始编号;
3)数组的读写:使用带索引的方括号表示法来指定数组元素;
(4)字符串
1)C风格字符串
a)C风格字符串有一种特殊的性质:以空字符结尾,空字符被写作\0,其ASCII码为0,用来标记字符串的结尾;
b)字符串的赋值有2种方式:前者是用数组赋值的方式,后者是用双引号的方式(用引号括起的字符串隐式地包括结尾的空字符)
char a[] = {‘t’,'e','s','t','\0'}; //若没有\0则表示数组而不表示字符串;
char a[] = "test";
PS:单引号‘’用于字符类型;双引号“”用于字符串类型;
c)标准头文件cstring(老式实现为string.h)提供了很多与字符串相关的函数的声明;
2)string类字符串
a)标准头文件string中定义了string类;
b)字符串读写:
string str=″China″;
str[0] = ‘C’;
(5)结构
1)结构是用户定义的类型,因此创建结构包括两步:首先定义结构描述;然后按描述创建结构变量;
2)结构的读写:结构变量使用成员运算符(.)来访问各个成员;
struct inflatable
{
char name[20];
float volume;
double price;
};
inflatable hat = {“Chinese”,1.0,1.1};
hat.price = 1.1;
PS:定义结构时不能直接设置默认值;
(6)共同体
1)共同体是一种数据格式,它能够存储不同的数据类型,但是只能同时存储其中的一种类型,也就是说结构体可以同时存储int,double和long,共同体只能存储int,double或long;
2)共同体的用途是为了节省空间,因为有的数据项可能会使用到多种数据类型,比如商品ID可能为数字也可能为字符串;
union inflatable
{
char name[20];
float volume;
double price;
};
inflatable hat;
hat.price = 1.1;
(7)枚举类型
1)enum 枚举名{ 枚举值表 };
2)在枚举值表中应罗列出所有可用值;这些值也称为枚举元素;
3)一般枚举元素为符号常量,对应整数值默认从0开始;也可以显式指定:
enum test{test1=1,test2=12};
test t = test1;
cout《t《endl;//输出1
(8)指针
1)指针是一个存放地址的变量:对指针变量应用运算符(*)可以获得该地址存储的值;(对变量应用地址运算符(&)可以获得它的地址)
2)声明指向特定类型的指针:typename*pointername;
3)初始化指针变量是一个很好的编程习惯,可以防止指针刚好指向程序所在内存空间;
int *p = NULL;
4)指针是C++内存管理编程的核心,在C++中使用new / delete来管理内存:
typeName*pointer_name = new typeName;
delete pointer_name;
a)typeName可以是基本类型,可以是结构,也可以是数组;
b)当typeName是数组时,应该使用[]:typeName*pointer_name = new typeName[];delete[] pointer_name;
5)64位机器,64位windows系统,x64编译平台上,指针变量为8个字节;64位机器,64位windows系统,win32编译平台上,指针变量为4个字节;
PS:
(1)C++需要提前声明变量并根据数据类型为变量申请内存空间;
(2)C++中定义常量:const;
2.语句
(1) for循环
for(initialization;test-expression;update-expression)
body
(2)while循环
while(test-condition)
body
(3)do while循环
do
body
while(test-expression);
(4)if else语句
if(test-condition)
statement1
else
statement2
(5)switch语句
switch(integer-expression)
{
case label1:statement(s)break;
case label1:statement(s)break;
...
default:statement(s)
}
(6)break和continue语句
break和continue语句都使程序能够跳过部分代码。可以在switch语句或者任何循环中使用break语句,是程序跳到switch或循环后面的语句处执行;continue语句用于循环中,让程序跳过循环体中余下的代码并开始新一轮循环;
typeName functionName(paraameterList)
{
statements
return value;
}
(2)函数原型
1)获得函数原型最简单的方法是,复制函数定义中的函数头,并添加分号;通常,在原型的参数列表中,可以包含变量名,也可以不包含;
2)通常在提供函数定义前,需要提供函数原型,目的是描述函数到编译器的接口;
3)函数原型经常隐藏在头文件中;
(3)库函数
1)库函数是已经定义和编译好的函数,同时可以使用标准库头文件提供其原型,因此只需正确地调用这种函数即可;
2)由于版权原因,库函数的源代码一般是不可见的,但在头文件中你可以看到它对外的接口库函数简介;
4.类与对象
class 类名
{
private:
//私有的行为或属性
protect:
//保护的行为或属性
public:
//公共的行为或属性
};
PS:
1)一般地类定义放在头文件中,类实现放在源码文件中(定义成员函数时使用作用域解析运算符::来标示函数所属的类);
2)无论类成员是数据成员还是成员函数,都可以在类的公有部分或者私有部分中声明它,但数据项通常放在私有部分,组成类接口的成员函数放在公有部分;数据成员不允许初始化;
3)公有成员函数是程序和对象的私有数据成员之间的桥梁,提供类对象和程序之间的接口;
(1)构造函数:构造新对象,初始化数据成员
1)构造函数属于类成员函数;
2)构造函数名与类名一样;
3)构造函数没有返回值,也没有被声明为void返回类型;
4)c++提供默认构造函数,不做任何工作;
(2)析构函数:完成清理工作
1)析构函数也属于类成员函数;
2)析构函数名:在类名前加上~;
3)析构函数跟构造函数一样,没有返回值和声明类型;但是与构造函数不同的是,析构函数没有参数;
4)c++提供默认析构函数;
(3)对象
1)定义:类名 对象名
2)对象成员的引用:
<对象名>.<数据成员>
<对象名>.<成员函数>(参数)
<对象指针>-><数据成员>
<对象指针>-><成员函数>(参数)
3)类的对象都有各自的数据成员,共用成员函数的代码;
(4)this指针:对象可以在类的成员函数中通过调用this指针来针对自身的数据成员进行操作;
(5)内联函数:
1)定义:函数实现前添加关键字inline(关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用);
2)内联函数与一般函数的不同之处只在于函数调用的处理:一般函数进行调用时,要将程序执行权转到被调用函数中,然后再返回到调用它的函数中;而内联函数在调用时,是将调用表达式用内联函数体来替换,因此内联函数执行效率更高(空间换取时间);
3)在类的内部定义了函数体的函数,被默认为是内联函数,而不管你是否有inline关键字;对于只在类中声明的函数,需要对类外的函数体定义添加inline关键字才可成为内联函数;
(6)继承/派生
公有继承:基类的公有和保护成员的访问属性在派生类中不变,而基类的私有成员在派生类中不可访问;
私有继承:基类的公有和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可访问;
保护继承:基类的公有和保护成员都以保护成员的身份出现在派生类中,而基类的私有成员在派生类中不可访问;
PS:默认为私有继承
2)派生类中由基类继承而来的成员的初始化工作还是由基类的构造函数完成,然后派生类中新增的成员在派生类的构造函数中初始化;
3)派生类构造函数的语法:
5.模板
(1)模板定义:模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性;模版可以分为两类,一个是函数模版,另外一个是类模版;
(2)函数模板的一般形式如下:
template <class / typename T>
返回类型 函数名(形参表)
{
//函数定义体
}
PS:template是一个声明模板的关键字,表示声明一个模板;关键字class与typename可互相替代;
(3)类模板的一般形式如下:
template < class / typename T >
class 类名
{
类定义
};
(4)STL(stand template library)标准模板库,该库包含了常用的基本数据结构和基本算法,其中常见的容器有:
1)栈:stack<元素类型> 栈名
2)队列:queue<元素类型> 队列名
3)向量:vector<元素类型> 向量名
4)链表:list<元素类型> 链表名
(三)常见小知识点
1.逗号表达式:(a,b)= b;
2.a++与++a的区别:前者先执行其余运算,再执行++,后者先执行++,再执行其余运算;
3.new与delete搭配使用,malloc与free搭配使用;两者的区别在于前者会调用构造函数与析构函数;
4.int *p = new int(12)与int *p = new int[12]的区别:前者表示整型变量且赋值为12,后者表示长度为12的整型数组;
5.转义字符:‘\’;其中‘\n’表示换行,‘\t’表示制表符,‘\\’表示‘\’,‘\+数字(八进制)’表示ASCII码中对应的字符;
6.构造函数不能是虚函数(没构造之前没有对象,没有对象就无法调用虚函数),析构函数可以是虚函数;
7.C++中,一个空类占1个字节的内存;若指定析构函数为虚函数,则占4个字节的内存(32位机子上)或8个字节的内存(64位机子上),存放指向虚函数表的指针;
8.多文件工程问题:一般有一个main.cpp,然后头文件放声明,其余cpp文件放实现;在main.cpp中包含头文件即可;头文件名与相应的cpp文件名一般一致;
9.全局变量与局部变量:
(1)全局变量是所有文件范围内可见;局部变量是函数范围内可见;且局部变量会覆盖全局变量,此时若需要使用全局变量,则应使用::符号;
(2)extern的使用:在a.cpp文件定义一全局变量,若需要在b.cpp中使用,则需使用关键字extern;
(3)static的使用:在a.cpp文件定义一全局变量,若使用static关键字修饰,则该全局变量只在该文件中可见,在b.cpp中不可见;
10.const int * p 与int * const p的区别:
若有:int a =1;
(1)const int * p = &a:表示指针p指向区域为常量,不可以通过*p来修改,但可以通过a来修改;
(2)int * const p表示指针p为常指针,不可以指向其他区域,但可以修改a来修改该区域的值;
11.浅拷贝与深拷贝:
(1)浅拷贝只拷贝指针,深拷贝会在堆中重新申请内存;
(2)典型例子:对象的复制时,若类中含有指针变量,则需自定义拷贝构造函数;默认的拷贝构造函数是浅拷贝
- class String
- {
- public:
- String(const String &other); //拷贝构造函数
- private:
- char *m_data; //用于保存字符串
- };
- String(const String &other)
- {
- int length = strlen(other.m_data);
- m_data = new char[length + 1];
- strcpy(m_data, other.m_data);
- }
13.执行‘3’-‘2’结果为整数1;执行3-‘2’结果不为1;
14.函数指针与指针函数
(1)指针函数是一个函数,其返回为指针;
(2)函数指针是一个指针,其指向函数;