一、C++的历史
C++的起源可以追溯到1979年,当时Bjarne.Stroustrup(本贾尼·斯特劳斯特卢普,各个翻译的名字不同的地⽅可能有所不同)在⻉尔实验室从事计算机科学和软件⼯程的研究⼯作。⾯对项⽬中复杂的软件开发任务,特别是模拟和操作系统的开发⼯作,他感受到了现有语⾔(如C语⾔)在表达能⼒、可维护性和可扩展性⽅⾯的不⾜。
1983年,Bjarne.Stroustrup在C语⾔的基础上添加了⾯向对象编程的特性,设计出了C++语⾔的雏形,此时的C++已经有了类、封装、继承等核⼼概念,为后来的⾯向对象编程奠定了基础。这⼀年该语⾔被正式命名为C++。
二、命名空间
命名空间的提出是由于在使用C语言过程中时,经常使用会命名到相同的函数名、变量名等,为了方便多人协作,也为了发便少记忆一些名称,便有了命名空间的诞生。
命名空间的关键字是namespace,其后跟着{},可以在花括号里定义一些函数,变量,以及类等。
命名空间的使用只要在所要的变量、函数等前面加上定义的命名空间的名称以及两个冒号,就如rand这个变量名,它在C语言库中是一个函数名,但当我在wzz这个命名空间中将他定义为一个整型变量,打印时只要加上wzz::就会打印出10。
#include <stdio.h>
#include <stdlib.h>
// 1. 正常的命名空间定义
// wzz是命名空间的名字,⼀般开发中是⽤项⽬名字做命名空间名。
namespace wzz
{
// 命名空间中可以定义变量/函数/类型
int rand = 10;
int Add(int left, int right)
{
return left + right;
}
}
int main()
{
// 这⾥默认是访问的是全局的rand函数指针
printf("%p\n", rand);
// 这⾥指定wzz命名空间中的rand
printf("%d\n", wzz::rand);
return 0;
}
要注意的是:
1.命名空间是定义在全局的,当然它也可以嵌套定义。
2.项⽬⼯程中多⽂件中定义的同名namespace会认为是同一个变量空间,不会产生冲突。
3.C++标准库都放在⼀个叫std(standard)的命名空间中。
嵌套定义的示例:
#include<stdio.h>
#include<iostream>
// 命名空间的嵌套
namespace wx
{
//命名空间1
namespace wzz
{
int rand = 1;
int Add(int left, int right)
{
return left + right;
}
}
// 命名空间2
namespace xzq
{
int rand = 2;
int Add(int left, int right)
{
return (left + right)*10;
}
}
}
int main()
{
printf("%d\n", bit::wzz::rand);
printf("%d\n", bit::xzq::rand);
printf("%d\n", bit::wzz::Add(1, 2));
printf("%d\n", bit::xzq::Add(1, 2));
return 0;
}
三、C++的输入与输出
1.<iostream>是Input Out Stream的缩写,即标准输入、输出流库。这里定义了标准的输入、输出 对象。
2.std::cin是istream类的对象,它主要⾯向窄字符(narrow characters(of type char))的标准输
⼊流。
3.std::cout是ostream类的对象,它主要⾯向窄字符的标准输出流。
4.std::endl是⼀个函数,流插⼊输出时,相当于插⼊⼀个换⾏字符加刷新缓冲区。
5.<<是流插⼊运算符,>>是流提取运算符。(C语⾔还⽤这两个运算符做位运算左移/右移)
6 使⽤C++输⼊输出更⽅便,不需要像printf/scanf输⼊输出时那样,需要⼿动指定格式,C++的输⼊输出可以⾃动识别变量类型,其实最重要的是C++的流能更好的⽀持⾃定义类型对象的输⼊输出。
7.cout/cin/endl等都属于C++标准库,C++标准库都放在⼀个叫std(standard)的命名空间中,所以要
通过命名空间的使用方式去用他们。
#include<iostream>
//展开命名空间,展开后可以不用加std::
using namespace std;
int main()
{
int a=1;
double b=2.687;
char c='x';
//打印初始定义的值
cout<<a<<' '<<b<<' '<<c<<' '<<endl;
//再次赋值
cin>>a>>b>>c;
//打印第二次赋值的内容
cout<<a<<' '<<b<<' '<<c<<' '<<endl;
return 0;
}
四、缺省参数
1.缺省参数是值当函数没有传递参数时,使用一个默认参数运行函数,这个参数的值就叫做缺省值。(有时也称缺省参数为默认参数)。
2.缺省参数也分为全缺省和半缺省。全缺省即全部参数都有缺省值,半缺省即部分参数有缺省值。
3.C++规定半缺省参数必须从右往左依次规定缺省值,但当你调用函数时,必须从左往右给参数,并且不可跳跃给参数。
4.当函数声明和函数定义分离时,不能在函数定义和函数声明中同时给参省值,一定要在函数声明中给缺省值。
#include<iostream>
void fun(int n=10)
{
cout<<n<<' '<<endl;
}
int main()
{
//未给参数,使用缺省值
fun( );
//使用给定参数
fun(20);
return 0;
}
五、函数重载
在C++支持在同一作用域出现同名函数,但他们的函数参数要不同,可以分为参数类型不同或参数个数不同或参数顺序不同。
要注意:
返回值不同不能作为重载条件
#include<iostream>
using namespace std;
// 1、参数类型不同
int Add(int left, int right)
{
cout << "int Add(int left, int right)" << endl;
return left + right;
}
double Add(double left, double right)
{
cout << "double Add(double left, double right)" << endl;
return left + right;
}
// 2、参数个数不同
void f()
{
cout << "f()" << endl;
}
void f(int a)
{
cout << "f(int a)" << endl;
}
// 3、参数类型顺序不同
void f(int a, char b)
{
cout << "f(int a,char b)" << endl;
}
void f(char b, int a)
{
cout << "f(char b, int a)" << endl;
}
// 返回值不同不能作为重载条件,因为调⽤时也⽆法区分
//void fxx()
//{}
//
//int fxx()
//{
// return 0;
//}
// 下⾯两个函数构成重载
// f()但是调⽤时,会报错,存在歧义,编译器不知道调⽤谁
void f1 ()
{
cout << "f()" << endl;
}
void f1 ( int a = 10)
{
cout << "f(int a)" << endl;
}
int main()
{
Add(10, 20);
Add(10.1, 20.2);
f();
f(10);
f(10, 'a');
f('a', 10);
return 0;
}
六、引用
1.引用的概念:
是给已存在的变量取一个别名,但它不会开辟新的空间,会和引用变量共用空间。就如孙悟空又叫齐天大圣,也叫美猴王。
运用方法:类型&引用别名=变量;
#include<iostream>
using namespace std;
int main()
{
int a = 10;
int& b = a;
int& d = a;
cout << a << ' ' << b << ' ' << d << ' ' << endl;
d = 20;
cout << a << ' ' << endl;
return 0;
}
2.引用的特性:
(1)引用在定义时必须赋值。
(2)一个变量可以有多个引用。
(3)引用一旦引用一个实体就不能引用其他实体。
3.引用实践
主要是于引用传参和引用做返回值中减少拷贝提高效率和改变引用对象时同时改变被引用对象。
#include<iostream>
using namespace std;
void fun(int &ra)
{
ra=30;
}
int main()
{
int a=10;
cout<<a<< ' '<<endl;
fun(a);
cout<<a<< ' '<<endl;
return 0;
}
4.const 引用
(1)用const修饰变量时,若要引用则要在其前面加const,若变量定义时未加const修饰,引用时可以加const。即引用时变量的权限可以缩小,不可以扩大。
(2)所谓临时对象就是编译器需要⼀个空间暂存表达式的求值结果时临时创建的⼀个未命名的对象,C++中把这个未命名对象叫做临时对象。
#include<iostream>
using namespace std;
int main()
{
const int a;
//这样会报错
// int &b=a;
const int&c=a;
return 0;
}
5.引用和指针的关系
(1)语法概念上引用是⼀个变量的取别名不开空间,指针是存储⼀个变量地址,要开空间。
(2)引用在定义时必须初始化,指针建议初始化,但是语法上不是必须的。
(3)引用在初始化时引用⼀个对象后,就不能再引用其他对象;而指针可以在不断地改变指向对象。
(4)引用可以直接访问指向对象,指针需要解引用才是访问指向对象。
(5)sizeof中含义不同,引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节,64位下是8byte)。
(6)指针很容易出现空指针和野指针的问题,引用很少出现,引用使用起来相对更安全⼀些。
七、inline
1.用inline修饰的函数叫做内联函数,编译时C++编译器会在调用的地方展开内联函数,这样调用内联函数就需要建立栈帧了,就可以提高效率。
2.但是inline对于编译器来说只是⼀个建议,即使你加了inline,编译器也可以选择在调用的地方不展开,不同编译器关于inline什么情况展开各不相同,因为C++标准没有规定这个。
3.inline适用于频繁调用的短小函数,对于递归函数,代码相对多⼀些的函数,加上inline也会被编译器忽略。
4.inline不建议声明和定义分离到两个文件,分离会导致链接错误。因为inline被展开,就没有函数地址,链接时会出现报错。
八、nullptr
C++中NULL可能被定义为字面常量0,或者C中被定义为无类型指针(void*)的常量。不论采取何种定义,在使用空值的指针时,都不可避免的会遇到⼀些麻烦,本想通过f(NULL)调用指针版本的
f(int*)函数,但是由于NULL被定义成0,调用了f(int?x),因此与程序的初衷相悖。f((void*)NULL);
调用会报错。
并且C++中的NULL其实是一种宏,看下面的代码:
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
在C++11中引入nullptr,nullptr是⼀个特殊的关键字,nullptr是⼀种特殊类型的字⾯量,它可以转换成任意其他类型的指针类型。使用nullptr定义空指针可以避免类型转换的问题,因为nullptr只能被隐式地转换为指针类型,而不能被转换为整数类型。