目录
1. C++与C的联系
- 都是编译性语言,采用静态编译
- 都是强类型语言(强类型指,变量的定义都需要规定数据类型),但是C++更强(更强指,C++的编译器对数据类型和语法的检查更加严格)
- C++兼容C语言
- C++相较C语言,增加了很多特性,全面支持面向对象编程,适合大型软件开发
2. C++编译方式
方式一:gcc 文件名.cpp -lstdc++
==方式二:g++ 文件名.cpp ==
3. C++文件常用文件后缀
1. 文件名.cpp
2. 文件名.cc
3. 文件名.C
4. 文件名.cxx
4. C++风格的C语言头文件
C++兼容C语言,可以使用C语言标准库函数,因此需要包涵相应的标C库头文件,但是头文件名需改写成C++风格(可以不改)
C语言风格:<头文件名.h>
对应C++风格:<C文件名>
以上两种头文件等价,例如:
<stdio.h> 等价于
5. 输入和输出
用cin对象表示标准输入
用cout对象表示标准输出
例如:
int i,j;
double k;
cin >> i >> j;//类似c语言中scanf("%d%d",&i,&j);
cin >> k;//类似c语言中scanf("%lf",&k);
int i = 517;
double j = 18.0;
char * str = "unicorn";
cout << i << ',' << j << ',' << str << endl;
//类似printf("%d,%lf,%s\n",i,j,str);
//endl作用类似'\n'
6. namespace(命名空间)关键字
作用:在多文件编程时,可能出现不同文件定义了同名、相同形参、相同返回值类型的函数或同名、相同数据类型的全局变量,这种情况下在编译链接时会报错,为了避免这种情况引入namespace概念,namespace用于避免大型软件开发中的名字冲突。命名空间对定义在其中成员的影响仅是限制了他们的可见性,对他们所处哪个数据端没有影响(即,对生命周期,作用域没有影响)
6.1 定义namespace
namespace 命名空间名{
成员1;
成员2;
...
...
}
成员数据类型可以是全局变量、函数、自定义类型、命名空间的嵌套,例如:
namespace linraffe{
int x;
void func(void){...}
struct zoo{...};
namespace unicorn{...}
}
6.2 namespace的使用方法
- 通过作用域限定符"::":命名空间名::要访问的成员名
举例:
namespace.cpp
#include <iostream>
namespace giraffe{
void func(void){
std::cout << "giraffe" << std::endl;
}
}
int main()
{
#ifndef GIRAFFE
func();
#endif
giraffe::func();
return 0;
}
编译执行:
Desktop Linraffe$ g++ namespace.cpp -o namespace
namespace.cpp:12:5: error: use of undeclared identifier 'func'; did you mean 'giraffe::func'?
func();
^~~~
giraffe::func
namespace.cpp:4:10: note: 'giraffe::func' declared here
void func(void){
^
1 error generated.
Desktop Linraffe$ g++ namespace.cpp -D GIRAFFE -o namespace
Desktop Linraffe$ namespace
giraffe
以上可见,不使用作用域限定符访问作用域giraffe中的成员函数func()
- 通过命名空间指令关键字using:using namespace 命名空间名;
使用场景:对于一些通用的,通常不会被编程人员使用的函数名、成员名(比如,printf()通常不会被人重写成自己的函数)每次都要使用作用域限定符很麻烦。使用“using namespace 命名空间名”后,指定的命名空间名中的成员均可见,不需要每次都加作用域限定符也可以成功访问,最常用的标准空间指令应用场景:
#include <iostream>
using namespace std;
namespace giraffe{
void func(void){
cout << "giraffe's func()" << endl;
}
}
namespace unicorn{
void func(void){
cout << "unicorn's func()" << endl;
}
}
int main(void)
{
using giraffe::func;
using namespace unicorn;
func();
unicorn::func();
return 0;
}
编译输出结果:
Desktop Linraffe$ namespace
giraffe's func()
unicorn's func()
以上,两个命名空间中的func()函数都被引入作用域并且可以共存,但是直接调用,实际被调的是通过命名空间声明的func()函数
通过命名空间指令和通过命名空间声明引入的成员的区别:
- 通过命名空间指令引入到指定作用域的成员类似从作用域外部引入的全局变量
- 通过命名空间声明引入到指定作用域的成员类似声明在作用域内部的局部变量(实际是全局变量)
- 调用当这以两种方式引入到同一作用域的同名成员时,规则类似C语言中在相同作用域中调用同名全局变量和局部变量可见性的规则 — “局部优先”
- 当同一作用域中同时以这两种方式引入同名成员,要调用以命名空间指令引入的成员(看作外部引入的全局成员),只能通过作用域限定符的方式。
6.3 无名命名空间
以下代码,输出结果是什么?
#include <iostream>
using namespace std;
namespace giraffe{
int num = 517;
}
int num = 109;
int main(void)
{
using giraffe::num;
cout << num << endl;
return 0;
}
编译输出结果:
517
根据上一小节最后的说明,giraffe命名空间中num被引入main函数的作用域,并被看作一个在mian函数中声明的局部变量,因此与它同名的全局变量在main中被隐藏了。
那么在这种情况下如何调用这个全局变量呢?为此引入无名命名空间概念:
不属于任何命名空间的标识符(变量名、函数名…),将被编译器自动放入无名命名空间中
显式访问无名命名空间的方法:"::标识符"
修改以上代码:
#include <iostream>
using namespace std;
namespace giraffe{
int num = 517;
}
int num = 109;
int main(void)
{
using giraffe::num;
cout << ::num << endl;
return 0;
}
编译输出结果:
109
6.4 命名空间的嵌套
定义了如下嵌套命名空间zoo
namespace zoo{
int num = 6;
namespace cage{
int num = 66;
namespace giraffe{
int num = 666;
}
}
}
如何访问命名空间giraffe中的num?
zoo::cage::giraffe::num;
7. 结构、联合、枚举
7.1 结构
- 与C语言不同,C++中定义结构体变量可以省略struct关键字,例如:
#include <iostream>
struct zoo {
char * animal;
int num;
};
int main(void){
struct zoo shanghai_zoo;//C语言定义结构体变量
zoo guangzhou_zoo;//C++定义结果体变量
return 0;
}
- 与C语言不同,C++中结构体里可以定义函数,成为成员函数,而且在成员函数中可以直接访问成员变量
7.2 联合(建议不使用)
- 与C语言不同,C++中定义联合体变量可以不使用union关键字
- 支持匿名联合
匿名联合举例:使用匿名联合测试主机字节序
#include <cstdio>
int main(void)
{
union{//匿名联合
unsigned int num;
unsigned char arr[4];
};
num = 0x12345678;
for(int i = 0; i < 4; i++){
printf("0x%x ",arr[i]);
}
printf("\n");
return 0;
}
输出结果:
0x78 0x56 0x34 0x12
7.3 枚举
- 与C语言不同,C++中定义枚举变量可以省略关键字enum
- 与C语言不同,C++中枚举是一个独立的类型,而C语言中枚举的实质是一组整形数,例如:
enum {spring = 1,summer,autumn,winter}season;
season = 3;//C语言中合法,在C++中不合法
season = autumn;//C、C++中都合法
8. 字符串
8.1 C++对C语言中字符串的兼容
一. C语言中字符串的形式:
- 双引号形式:“giraffe”
- 字符指针形式:char * p = “giraffe”;
- 字符数组形式:char arr[] = “giraffe”;
二. C语言字符串操作可能的错误形式
char * p = “unicorn”;
char arr[] = “giraffe”;
- strcpy(“giraffe”,p)//段错误,试图对只读的代码段数据
- strcpy(arr,“giraffe&unicorn”);//越界使用,危险
- arr = p;//数组名可看作指针,但是指向不可改变,数组名arr可看作 char const * arr
8.2 C++表示字符串的数据类型(实质是一个类)string
- 定义字符串
#include <string>//如果已经引入标准命名空间可以不写
string s = "giraffe";//字符串定义初始化
- 字符串操作
//赋值操作:'='
string str_1 = "linka";
string str_2 = "giraffe";
str_1 = str_2;//将str_2赋值给str_1
//连接操作:'+'、"+="
string str_1 = "linraffe ";
string str_2 = "unicorn";
string str_3 = str_1 + str_2;//str_1与str_2进行拼接
str_1 += str_2;//将str_1与str_2进行拼接后的字符串赋值给str_1
//比价操作:'>'、'<'、"=="、"!="、">="、"<="
str_1 == str_2//比较str_1和str_2是否先等,返回真或假
- 字符串相关的函数(string类的成员函数)
size()、length()//获取字符串长度(不计算结尾的'\0')
string str_1 = "giraffe";
cout << str_1.size() << endl;//返回“giraffe”的长度
cout << str_1.length() << endl;//作用同上
c_str()//实现将string类字符串转化为C语言字符串,返回const char *字符串
string str_2 = "unicorn";
const char * p = str_2.c_str();//将"unicorn"以const char *的形式给p
- string类字符串可以当作字符数组来使用
string str_1 = "giraffe";
str_1[0] = "G";
9. C++的布尔类型
- bool类型是C++中的基本数据类型,专门表示逻辑值:1/true 和 0/false(识别true和false效果同1和0)
- bool类型在内存中占一个字节
- bool类型的变量可以接受任意变量和表达式的值,其值非0为真(true),为0(或NULL)则为假(false)