概述
???? ???? 努力到无能为力,拼搏到感动自己。
???? ???? 今天要向各位小伙伴们介绍的是 c++入门语法 :
文章目录
- ???? 一、关键字
- ???? 二、命名空间
- ???? 1、命名空间定义
- ???? 2、命名空间的使用
- ????三、输入&输出
- ???? 四、缺省参数
- ???? 1、缺省参数定义
- ???? 2、参数缺省的场景
- ???? (1)全缺省参数
- ???? (2)半缺省参数
- ????五、函数重载
- ???? 1、函数重载概念
- ???? 2、函数重载实例
- ???? 六、引用
- ???? 1、引用的概念
- ???? 2、引用的特点
- ???? 3、引用的场景
- ???? (1)做参数
- ???? (2)做返回值
- ???? 4、传值和传引用
- ???? 5、引用和指针
- ???? 七、内联函数
- ???? 1、内联函数的概念
- ???? 2、内联函数的特点
- ???? 八、C++11
- ???? 1、auto关键字
- ???? (1)简介
- ???? (2)auto的使用场景
- ???? 2、范围for循环
- ???? 3、nullptr
???? 一、关键字
⚓️简介:关键字属于保留字,是整个语言范围内预先保留的标识符。每个C++关键字都有特殊的含义。经过预处理后,关键字从预处理记号中区别出来,剩下的标识符作为记号,用于声明对象、函数、类型、命名空间等。
???? 注意❗️ ❗️
???? 不能声明与关键字同名的标识符。
???? 二、命名空间
⚓️ 目的:对标识符的名称进行本地化,以避免命名冲突或名字污染。
???? 1、命名空间定义
???? <1>直接命名 (namespace 自定义名称 {})
???? <2>命名空间可以嵌套(可以多个嵌套)
???? 代码⬇️ ⬇️ :
//命名空间的定义和嵌套
namespace N
{
int a = 10;
namespace N1
{
int a = 20;
namespace N2
{
int a = 30;
}
}
}
???? 注意❗️ ❗️
???? 当同一个工程中存在多个相同名称的命名空间,相同名称的命名空间会合并到一起。
???? 2、命名空间的使用
???? <1>命名空间名称加作用域限定符
???? 代码⬇️ ⬇️ :
int main() {
int a = 0;
cout << a << endl;
cout << N::a << endl;
cout << N::N1::a << endl;
cout << N::N1::N2::a << endl;
return 0 ;
}
???? <2>using加命名空间成员
???? 代码⬇️ ⬇️ :
using std::cout;
using std::cin;
using std::endl;
???? <3>using namespace加命名空间
???? 代码⬇️ ⬇️ :
using namespace std;
????三、输入&输出
⚓️ cin:标准输入流
⚓️ cout:标准输入流
???? (1)使用cin输入或cout输出时要包含头文件 (没有“.h”,旧编译器(vc 6.0)中还支持<iostream.h>格式,后续编译器已不支持,因此推荐使用 +std的方式。)。
???? (2)cin和cout都存在于std标准命名空间中,“::”是作用域限定符。
???? 注意❗️ ❗️
???? (1)输入和输出都不需要去增加数据格式控制如%d,%c,其可以自动识别。
???? (2)在C++中是兼容C的,C中的语法内容在C++中一样可以使用。
???? (3)C中的标准输入函数scanf,标准输出函数printf与C++中的cin,cout各有优劣,使用时应该视情况而定。
???? 四、缺省参数
⚓️ 大家知道备胎是什么吗?
???? 1、缺省参数定义
⚓️ C++中,在相较于C的基础上引入了缺省参数。缺省数是声明或定义函数时为函数的参数指定一个默认值。在调用该函数时,如果没有指定实参则采用该默认值,否则使用指定的实参。
???? 2、参数缺省的场景
???? (1)全缺省参数
???? 代码⬇️ ⬇️ :
void DatePrint(int year = 0, int month = 1, int day = 1)
{
cout << year <<"年" <<month<<"月" <<day<< "日" << endl;
}
???? 注意❗️ ❗️
???? 当我们需要进行函数的声明和定义时,在进行声明的时候就给参数指定默认值,后面的定义就不需要指定默认值了。
???? (2)半缺省参数
???? 代码⬇️ ⬇️ :
void TestFun1(int a, int b = 3, int c = 4)
{
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
}
???? 注意❗️ ❗️
???? 1.半缺省参数必须从右往左依次来给出,不能间隔着给。
???? 2. 缺省参数不能在函数声明和定义中同时出现(一般在进行声明时就给参数指定默认值)。
????五、函数重载
???? 1、函数重载概念
⚓️ 重载:自然语言中,一个词可以有多重含义,人们可以通过上下文来判断该词真实的含义,即该词被重载了。
⚓️ 函数重载的概念:重载函数是函数的一种特殊情况,为使用方便,C++允许在同一作用域中声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同,也就是说用同一个函数完成不同的功能。重载函数常用来实现功能类似而所处理的数据类型不同的问题。
???? 2、函数重载实例
???? 代码⬇️ ⬇️ :
int TestFun(int a, int b, int c)
{
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
return 0;
}
//(1)参数的类型不同
int TestFun(double a, int b, double c)
{
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
return 0;
}
//(2)参数的类型顺序不同
int TestFun(double a, double b, int c)
{
cout << "a=" << a << endl;
cout << "b=" << b << endl;
cout << "c=" << c << endl;
return 0;
}
//(3)参数个数不同
int TestFun(int a, int b)
{
cout << "a=" << a << endl;
cout << "b=" << b << endl;
return 0;
}
???? 注意❗️ ❗️
???? 当函数只有返回值类型不同的时候,不构成函数重载。
????思考(面试题):为什么C++中支持函数重载,而C语言中不支持?
????思考(面试题):C++能否将一个函数按照C的风格进行编译?
???? 六、引用
???? 1、引用的概念
⚓️ 引用(reference)是C++对C语言的重要扩充。引用就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样。
???? 2、引用的特点
???? (1)引用在定义时必须要初始化。
???? (2)一个变量可以有多个引用。
???? (3)在作用域内同一个引用不能对多个对象使用。
???? (4) 引用是一种独立的类型。
???? 代码⬇️ ⬇️ :
void Test(int& a)
{
cout << a << endl;
}
void Test(int a)
{
cout << a << endl;
}
???? 注意❗️ ❗️
???? 这两个函数的定义构成了重载。
???? (5)常引用
???? 代码⬇️ ⬇️ :
void Test()
{
const int a = 10;
//int& ra = a; // 该语句编译时会出错,a为常量
const int& ra = a;
// int& b = 10; // 该语句编译时会出错,b为常量
const int& b = 10;
double d = 12.34;
//int& rd = d; // 该语句编译时会出错,类型不同
const int& rd = d;
}
???? 3、引用的场景
传引用的优点:
???? (1)函数形参和实参是同一个对象,也就不存在对象复制,减少调用函数的开销。
???? (2)可以在修改形参的同时对实参的修改.
???? (1)做参数
???? 代码⬇️ ⬇️ :
int cp(int& a, int& b)
{
if (a > b)
return a;
else
return b;
}
???? (2)做返回值
???? 代码⬇️ ⬇️ :
int& Count()
{
static int n = 0;
n++;
// ...
return n; }
???? 注意❗️ ❗️
???? 当使用函数返回值引用,返回值不能是局部变量,因为局部变量离开自己的作用域后,会被自动销毁。
???? 4、传值和传引用
⚓️ 比较:在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时拷贝,因此用值作为参数或者返回值类型,效率较低,尤其是当参数或者返回值类型非常大时,效率就更低。
⚓️ 通过测试,我们可以得到更加直观的对比。
???? <1>作为参数
???? 代码⬇️ ⬇️ :
#include <time.h>
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{
A a;
// 以值作为函数参数
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(a);
size_t end1 = clock();
// 以引用作为函数参数
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(a);
size_t end2 = clock();
// 分别计算两个函数运行结束后的时间
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
???? <2>作为返回值
???? 代码⬇️ ⬇️ :
#include <time.h>
struct A{ int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a;}
// 引用返回
A& TestFunc2(){ return a;}
void TestReturnByRefOrValue()
{
// 以值作为函数的返回值类型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作为函数的返回值类型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 计算两个函数运算完成之后的时间
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl; }
???? 总结:通过上面两个代码,我们可以发现,在某些场景下选用传引用有着更大的优势。
???? 5、引用和指针
???? ???? 相同点:
⏳ (1)通过引用和指针,我们都可以实现在函数的调用过程中,完成对实参的改变。
⏳ (2)引用和指针的本质都是地址,初始化的汇编代码一模一样(如图)
???? ???? 不同点:
⌛️ (1)引用在其作用域内在被初始化后,不可改变。而指针指向的地址可以发生改变。
⌛️ (2)指针是一种变量,在定义指针时会开辟空间。而引用是对原对象取别名,不会开辟额外的空间。
⌛️ (3)指针和引用的自增自减运算不一样。
⌛️ (4)sizeof(指针)和sizeof(引用)不一样,前者获得的是存放指针变量的空间大小,而后者是原对象的大小。
⌛️ (5)没有NULL引用,有NULL指针。
⌛️ (6)没有多级引用的说法,存在多级指针。
⌛️ (7)访问实体方式不同.。指针需要显式解引用,引用则编译器自己处理。
⌛️ (8)引用比指针使用起来相对更安全。
⌛️ (9)引用在定义时要求必须初始化,而指针没有要求。
???? 总结:C++中的引用相比与指针而言,在概念上更好理解,一定程度上避免了野指针和越界问题,有着更加良好的安全性。
????思考(面试题):请说明指针和引用的区别与联系。
???? 七、内联函数
???? 1、内联函数的概念
⚓️ 内联函数:以inline修饰的函数叫做内联函数。编译时C++编译器会在调用内联函数的地方展开,没有函数压栈的开销,内联函数提升程序运行的效率。
???? 2、内联函数的特点
???? (1)内联函数每次调用时直接展开,避免了函数额外开销。但是代码复杂的函数以及递归循环就不适合写成内联函数,内联函数的本质是以时间换空间。(通过反汇编可以观察)
???? (2)当我们写成的内联函数内部有递归循环时,编译器会自动忽略内联,因为inline对编译器而言只是一种建议,编译器会自动优化。
???? (3)内联函数不建议将声明和定义分离,因为当内联函数展开之后,就没有函数地址了,链接会找不到。
???? 代码⬇️ ⬇️ :
//Swap.h
#pragma once
#include<iostream>
using std::cout;
using std::endl;
using std::cin;
inline void Swap(int& a, int& b);
//Swap.cpp
#include"Swap.h"
void Swap(int& ra, int& rb)
{
int tmp = ra;
ra = rb;
rb = tmp;
}
//test.cpp
#include"Swap.h"
int main() {
int a = 1;
int b = 2;
Swap(a, b);
cout << a << " " << b << endl;
return 0;
}
//错误链接 LNK2019 无法解析的外部符号 "void __cdecl Swap(int &,int &)" (?Swap@@YAXAEAH0@Z),函数 main 中引用了该符号
???? 注意❗️ ❗️
???? 当我们把声明和定义分开后,程序就会报错如上(链接错误)。
???? 总结:当函数代码比较简单并且没有递归和循环时,我们可以将它写成内联函数来提高效率。同时内联函数的声明和定义最好不要分离。
????思考(面试题):C++中为什么不推荐使用宏?并采用了什么手段来代替宏?
???? 八、C++11
???? 1、auto关键字
???? (1)简介
⚓️ 在早期C/C++中,auto修饰变量是具有自动存储类型的局部变量(遗憾没人使用)。在C++11中,标准委员会废除了auto原本的意义(避免混淆),同时把它作为一个新的类型指示符来指示编译器。auto的变量类型必须由编译器在编译时推导获得。
???? 注意❗️ ❗️
???? (1)使用auto定义变量时必须进行初始化,因为编译器在编译时会根据初始化的内容来判断auto定义变量的类型。
???? (2)auto不是类型的声明,而是一种类型的“占用符”,在编译器进行编译时会自动将auto替换成对应的类型。
???? (2)auto的使用场景
???? <1>auto和指针、引用进行配合。
???? 代码⬇️ ⬇️ :
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int main() {
int a = 1;
//使用auto定义指针类型时
//auto和auto*没有区别
auto b = &a;
auto* c = &a;
auto& d = a;
//typeid().name()是用来打印类型的
cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
cout << typeid(d).name() << endl;
return 0;
}
???? 注意❗️ ❗️
???? 使用auto定义指针类型时,auto和auto*没有区别。
???? <2>同一行可以定义多个变量。
???? 代码⬇️ ⬇️ :
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int main() {
int a = 0;
auto& ra = a, & rra = a, & rrra = a;
//此代码会报错无法推导类型
//auto& ra = a, *pa=a;
return 0;
}
???? 注意❗️ ❗️
???? 使用auto在同一行定义多个变量时,同一行变量的类型要相同。因为编译器会推导的第一个类型,并用推导出的类型去定义其他的变量。
???? <3>auto不能成为函数的参数。
???? 代码⬇️ ⬇️ :
void TestFun(auto x);
void TestFun(auto x)
{
}
//报错:此处不能使用auto
???? 注意❗️ ❗️
???? 报错:此处不能使用auto。
???? <4>auto不能定义数组。
???? 代码⬇️ ⬇️ :
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
int a[10] = { 0 };
auto b[10] = { 0 };
//报错:auto类型不能出现在顶级数组中
cout << b << endl;
return 0;
}
???? 注意❗️ ❗️
???? 报错:auto类型不能出现在顶级数组中。
???? 2、范围for循环
⚓️ 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。
???? 代码⬇️ ⬇️ :
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
//在C++11中,使用初始化列表对数组、枚举等类型进行初始化时,
//可以省略等号。
int arr[10]{0,1,2,3};
for (auto e : arr)
cout << e << " ";
return 0;
}
???? 注意❗️ ❗️
???? continue和break在范围for中仍然适用。
???? 3、nullptr
⚓️ 在C/C++,我们要养成良好的习惯,即定义变量的时候,同时给变量初始化,避免引发糟糕的结果。例如指针:如果没有初始化,就会引发野指针问题,可能会干扰到其他正在运行的程序。
而对指针初始化的方式就是给它置成空。
???? 代码⬇️ ⬇️ :
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
int main()
{
int* p1 = 0;
int* p2 = NULL;
return 0;
}
⚓️ 其中NULL实际是一个宏,在传统的C头文件(stddef.h)中,我们可以看到如下:
???? 代码⬇️ ⬇️ :
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif
⚓️ 但是在使用空指针时,不可避免的会有一定麻烦。
???? 代码⬇️ ⬇️ :
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
//当我们我传递空指针时
void Fun(int x)
{
cout <<"int" << endl;
}
void Fun(int* x)
{
cout << "int*" << endl;
}
int main() {
Fun(0);
Fun(NULL);
//强制转换成int*类型
Fun((int*)NULL);
Fun(nullptr);
return 0;
}
//结果为:int int int* int*
⚓️ 原程序中本是想要传递空指针,但是NULL被替换成了0,输出的就是int。除非将NULL强制转换成(int*)类型才能输出(int*)。
⚓️ 在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。
???? 注意❗️ ❗️
???? (1)为了避免上述情况,C++11中引入了nullptr关键字,作为关键字,不需要引用头文件。
???? (2)为了提高代码的健壮性,建议表示空指针时使用nullptr。
今天的内容到这里就结束了,关于本期提出的思考题,希望老铁们可以仔细想想,我们下期再谈 。???? ????
???? ???? 每天早上叫我们起床的不是闹钟,而是梦想。
???? ???? 愿与诸君共勉!
最后
以上就是听话小松鼠为你收集整理的C++入门超详解(1)???? 一、关键字???? 二、命名空间????三、输入&输出???? 四、缺省参数????五、函数重载???? 六、引用???? 七、内联函数???? 八、C++11的全部内容,希望文章能够帮你解决C++入门超详解(1)???? 一、关键字???? 二、命名空间????三、输入&输出???? 四、缺省参数????五、函数重载???? 六、引用???? 七、内联函数???? 八、C++11所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复