目录
0 C++入门
C++是在C的基础之上,容纳进去了面向对象编程思想,并增加了许多有用的库,以及编程范式等。熟悉C语言之后,对C++学习有一定的帮助,本章节主要目标:
- 补充C语言语法的不足,以及C++是如何对C语言设计不合理的地方进行优化的,比如:作用域方面、IO方面、函数方面、指针方面、宏方面等。
- 为后续类和对象学习打基础。
以下是最简单的一个C++程序。
#include<iostream>
using namespace std;
int main()
{
cout << "hello word" << endl;
return 0;
}
1 关键字
C++总计63个关键字,C语言32个关键字。
2 命名空间
2.1 域
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存
在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化,
以避免命名冲突或名字污染,namespace关键字的出现就是针对这种问题的。
- C++可以解决C语言无法解决的一些情况。
#include<stdio.h>
#include<stdlib.h>
int rand = 10;
// rand命名冲突
int main()
{
printf("%d\n", rand);
return 0;
}
- 报错原因就是stdlib里面也有名为rand的函数,重定义了rand。
C语言中同一个域不能定义同一个变量,不同域可以定义同一变量。【就近原则】
- 我们知道,直接在main里输出x会输出的是1。那么如何输出全局变量x(0)?
- ::域作用限定符
域:全局域 局部域(默认) 命名空间域 类域
#include<stdio.h>
int x = 0;
int main()
{
int x = 1;
printf("hello world\n");
printf("%d\n", x);
printf("%d\n", ::x);
return 0;
}
这样就可以输出0。
::域作用限定符
- 域 :: 变量
- 无域作用限定符 :: 先局部在整体
- 有域作用限定符 :: 直接去指定的域里面搜索
- 如果 :: 前是空白,则就是在全局域里面搜索
- 如果 :: 前有指定的域,直接去指定域里面搜索
#include<stdio.h>
#include<stdlib.h>
namespace bit1
{
int x = 0;
}
namespace bit2
{
int x = 1;
}
int x = 9;
int main()
{
int x = 7;
printf("%d\n", bit1::x); //0
printf("%d\n", bit2::x); //1
printf("%d\n", x); //7
printf("%d\n", ::x); //9
return 0;
}
编译器搜索原则
- 不指定域:先当前局部域再全局域
- 指定域:直接去指定域搜索
全局域 生命周期 访问- 局部域 生命周期 访问
- 命名空间域 访问
- 类域
类似于以下关系:
自家菜地相当于局部变量,不需要指定,可以直接默认访问。老王家、张阿姨家菜地相当于命名空间域,需要指定了才能去用,野菜相当于全局变量,也不需要指定。
- 如果想要输出全局变量rand ,那么就要用namespace关键字将其封装,然后指定输出。
2.2 命名冲突
- 冲突1:头文件的函数/库会与程序员自己写的全局变量/函数等命名冲突。
就比如stdlib.h里面的rand和自己写的rand冲突。
- 冲突2:在项目当中,两个程序员在不同的文件中写相同的命名的变量,最后合并到一起时会冲突。
合并一起时,不会说bit1和bit1冲突(因为编译器会自动合并同名命名空间),而是说该相同名称的变量冲突。
#include<stdio.h> #include<stdlib.h> namespace bit1 { int x = 0; } namespace bit1 { int x = 1; } int main() { printf("%d\n", bit1::x); return 0; }
命名空间中可以定义变量/函数/类型
namespace bit
{
// 命名空间中可以定义变量/函数/类型
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
struct Node
{
struct Node* next;
int val;
};
}
- 报错:“Node”:“struct”类型重定义
//test.c
#include<stdio.h>
#include"List.h"
#include"Queue.h"
//List.h
#pragma once
//双向链表
struct Node
{
int val;
struct Node* next;
struct Node* prev;
};
void Init(struct Node* phead);
void Push(struct Node* phead, int x);
//Queue.h
#pragma once
//栈
struct Node
{
int val;
struct Node* next;
};
struct Queue
{
struct Node* head;
struct Node* tail;
};
void Init(struct Node* pq);
void Push(struct Node* pq, int x);
要分别用命名空间域!!
2.3 命名空间定义
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{ }即可,{ }中即为命名空间的成员。
- 命名空间中可以定义变量/函数/类型
namespace N { //变量 int rand = 10; //函数 int Add(int left, int right) { return left + right; } //结构体 struct Node { struct Node* next; int val; }; }
- 命名空间可以嵌套
//命名空间可以嵌套 namespace N1 { int a; int b; int Add(int left, int right) { return left + right; } namespace N2 { int c; int d; int Sub(int left, int right) { return left - right; } } }
N1::N2::Sub
- 命名冲突问题
2.4 命名空间使用
命名空间的使用有三种方式:
- 加命名空间名称及作用域限定符(变量/函数/结构体/嵌套等)
- 不展开,用的时候才展开
int main() { printf("%d\n", N::a); return 0; }
- 使用using将命名空间中某个成员引入
- 只展开常用的
using N::b; int main() { printf("%d\n", N::a); printf("%d\n", b); return 0; }
- 使用using namespace 命名空间名称 引入
- 直接全展开,这种方式只适合练习的时候用,写项目的时候还是倾向于用第一种。
using namespce N; int main() { printf("%d\n", N::a); printf("%d\n", b); Add(10, 20); return 0; }
- C++库里的头文件基本都不带.h
3 C++输入&输出
输出
#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
cout << "Hello world!!!" << endl; //endl等价于换行符
return 0;
}
- <<是流插入运算符,>>是流提取运算符。但是<< >> 也可以表示左移右移。C++会自动识别类型,如下:
#include<iostream>
// std是C++标准库的命名空间名,C++将标准库的定义实现都放到这个命名空间中
using namespace std;
int main()
{
// 1、<< 左移
int i = 100;
i = i << 1; //i==200
const char* str = "hello world";
char ch = '\n';
// 2、<< 流插入 自动识别类型
cout << str << i << ch;
printf("%s%d%c", str, i, ch);
return 0;
}
输入
- 流提取:>>
- 两种方法,注意C语言写法的输入,第二个字符类型打不出来,因为点了回车键后会把回车键当作字符吞掉,所以只输出了90。
说明
- 使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件以及按命名空间使用方法使用std。
- cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出他们都包含在<iostream >头文件中。
- <<是流插入运算符,>>是流提取运算符。
- 使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式。 C++的输入输出可以自动识别变量类型。
- 实际上cout和cin分别是ostream和istream类型的对象,>>和<<也涉及运算符重载等知识,这些知识我们我们后续才会学习,所以我们这里只是简单学习他们的使用。后面我们还有一个章节更深入的学习IO流用法及原理。
注意
要灵活使用C++和C语言的语法。比如C++并不能控制浮点型小数点输出个数的限制。
到这里为止,我们并没有发现C++在哪里补足了C语言的缺陷,只是提供了一种新的写法。