C++入门基础知识

目录

命名空间

定义

使用

嵌套

合并

C++的输入和输出

输出

输入

缺省参数

概念

分类

全缺省参数

半缺省参数

函数重载

1.参数类型不同

2.参数个数不同

3.参数类型顺序不同

引用

概念

特性

常引用

1.作为参数

2.作为返回值

运用

指针和引用区别

内联函数

概念

特性

auto关键字

1.根据右侧的变量,自动推导出类型

2.特殊的auto-for遍历

使用

1. auto与指针和引用结合起来使用

 2.同一行定义多个变量

指针空值nullptr


命名空间

在C语言中,我们会对变量,函数进行命名,但是会遇到名字相同而造成访问冲突的问题,那么在C++中,便有了一个“命名空间”的概念

定义

定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可,{}

中即为命名空间的成员。

namespace an
{
    int rand=10;

    int Add(int left,int right)
    {
        return left+right;
    }
    
    struct Node
    {
        struct Node* next;
        int data;
    }
}

使用

1.部分展开,需要用到命名空间名称以及作用域限定符"::"

int main()
{
    printf("%d",an::rand);
    printf("%d",an::Add(1,2));
    struct an::Node node;
    return 0;
}

2.使用using将命名空间中某个成员代入

using an::rand;
int main()
{
    printf("%d",rand);
    printf("%d",an::Add(1,2));
    return 0;
}

3.直接将命名空间名称引入

using namespace an;
int main()
{
    printf("%d",rand);
    printf("%d",Add(1,2));
    struct Node node;
    return 0
}

嵌套

命名空间也可以嵌套,那么需要多次用到作用域限定符

namespace an1
{
    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;
        }
    }
}

int main()
{
    printf("%d",an1::a);
    printf("%d",an1::N2::c);
    return 0;
}

合并

概而言之,就是一个工程里有多个同名的命名空间,最后编译器会将其整合,形成同一个命名空间,但注意的是,函数和变量不能有相同的名字,会导致重定义

//Test1.h
namespace an
{
	void Test1Init()
	{
		cout << "Test1Init" << endl;
	}

	namespace an1
	{
		int rand = 1;
	}
}

//Test2.h
namespace an
{
	typedef struct Stack
	{
		int* a;
		int top;
		int capacity;
	}ST;
}

C++的输入和输出

输出

C语言中,我们是用printf()输出函数来输出数据,那么在C++中呢?

首先C语言的printf函数需要一个stdio.h函数库,相同的,C++需要一个std的命名空间,因为C++将标准库(iostream)的定义实现都放入在这个命名空间中

简单实现:

#include<iostream>
using namespace std;
int main()
{
    cout<<"Hello world"<endl;
    return 0;
}

其中endl代表空格。

1.使用cout标准输出对象(控制台)和cin标准输入对象(键盘)时,必须包含< iostream >头文件

以及按命名空间使用方法使用std。

2.cout和cin是全局的流对象,endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。

3.<<是流插入运算符,>>是流提取运算符。

输入

通过cin和>>进行输入

#include<iostream>
using namespace std;
int main()
{
    int b;
    cin>>b;
    cout<<b<<" ";
    return 0;
}

若是多个数据输入,则按照先后顺序从左到右放置输入即可

int b,c;
cin>>b>>c;

值得一提的是,C++的输入输出会自动识别变量类型,不需要%d %f %lf这些繁琐的识别符

除此之外,std作为标准库的命名空间,为了方便,我们使用代码即可

using namespace std;

这样标准库里的函数都会显示出来,方便我们使用

缺省参数

概念

缺省参数是声明或定义函数时为函数的参数指定一个缺省值。在调用该函数时,如果没有指定实 参则采用该形参的缺省值,否则使用指定的实参。

void Func(int a=0)
{
    cout<<a<<endl;
}

int main()
{
    Func();//若不传入参数,那么就会使用事先定义好的值
    Func(10);//传入参数就用传入参数的值

    return 0;
}

分类

全缺省参数

意思即为所有参数都提前定好值

void Test(int a=10,int b=20,int c=30)
{
    cout<<"a="<<a<<endl;
    cout<<"b="<<b<<endl;
    cout<<"c="<<c<<endl;
}

半缺省参数

意思即为部分参数没有定好值

 void Func(int a, int b = 10, int c = 20)
 {
     cout<<"a = "<<a<<endl;
     cout<<"b = "<<b<<endl;
     cout<<"c = "<<c<<endl;
 }

注意:

1. 半缺省参数必须从右往左依次来给出,不能间隔着给

2. 缺省参数不能在函数声明和定义中同时出现

函数重载

C语言中,不能存在两个相同的函数名,但是在C++中,可以同时有多个相同函数名的函数

C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。

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 x()
{
    cout<<"f()"<<endl;
}

void x(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 f(int a, char b)
{
     cout << "f(int a,char b)" << endl;
}

int f(char b, int a)
{
     cout << "f(char b, int a)" << endl;
}

引用

概念

引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空 间,它和它引用的变量共用同一块内存空间。

int main()
{
	int a = 0;
	int& b = a;//a和b本质上一样,地址也一样
	
	cout << &a << endl;
	cout << &b << endl;
	
	b++;
	cout << b << endl;//1
	cout << a << endl;//相加的内容也是一样的
	a++;
	cout << a << endl;//2
	return 0;
}

ps:引用类型必须和引用实体是同种类型的

特性

1. 引用在定义时必须初始化

2. 一个变量可以有多个引用

3. 引用一旦引用一个实体,再不能引用其他实体

void Test()
{
    int a=10;
    int&b;//错误

    int& c=a;//a变量可以多个引用
    int& d=a;
    
    int b=20;    
    int&e =a;
    int&e =b;//错误,已经引用了,不能再引用其他实体,也就是覆盖


}

常引用

1.作为参数

void Swap(int& left,int& right)
{
    int tmp=left;
    left=right;
    right=tmp;
}

2.作为返回值

int& Count()
{
   static int n = 0;
   n++;
   // ...

   return n;
}

ps!!!

对于这个代码

int& Add(int a, int b)
{
    int c = a + b;
    return c;
}

int main()
{
    int& ret = Add(1, 2);
    Add(3, 4);
    cout << "Add(1, 2) is :"<< ret <<endl;
    return 0;
}

返回的是随机值——为什么?

因为在运行函数Add的时候,会临时开辟一个Add函数的空间,此时用ret作为Add的别名,也就是ret和Add同一个空间,但是当Add结束后,空间会被收回释放,那么此时ret的值就会发生改变,可能不是原来需要的函数值,会变成随机值

由此可得:

若不清栈帧,那么函数Add运行的值便是ret的值
若清除栈帧,那么就会返回随机值,因为函数的栈帧空被销毁,ret和Add的空间是同一个,所以会返回随机值 ,这要根据编译器来决定

运用

对于顺序表,C语言代码是这样的

struct SeqList
{
	int a[10];
	int size;
};

int SLAT(struct SeqList* ps, int i)
{
	assert(i < ps->size);

	return ps->a[i];
}
//修改第i个位置的值
void SLModifystruct(SeqList* ps, int i, int x)
{
	assert(i < ps->size);

	ps->a[i] = x;
}

需要用两个函数来实现输入和读取

对于C++

int& SLAT(struct SeqList& ps, int i)//引用后ps就不是一个指针,而是可以视为实参结构体
{
	assert(i < ps.size);
	return ps.a[i];
	//用结构体直接引用数组,因为结构体是定义在主函数里的,出SLAT函数后数组里的值还存在不会影响
}

int main()
{
	//由于函数加上了引用,故可以根据别名直接修改第n个位置的值,别名直接修改!(侧面修改了对应的函数值)
	struct SeqList s;
	s.size = 3;
	SLAT(s, 0) = 10;
	SLAT(s, 1) = 20;
	SLAT(s, 2) = 30;
	cout << SLAT(s, 0) << endl;//获取第n个位置的值并且打印
	cout << SLAT(s, 1) << endl;
	cout << SLAT(s, 2) << endl;
	return 0;
}

更多用法以后再讨论

指针和引用区别

在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。

int main()
{
     int a = 10;
     int& ra = a;
     
     cout<<"&a = "<<&a<<endl;
     cout<<"&ra = "<<&ra<<endl;
     return 0;
}

在底层实现上实际是有空间的,因为引用是按照指针方式来实现的。

int main()
{
     int a = 10;
 
     int& ra = a;
     ra = 20;
 
     int* pa = &a;
     *pa = 20;
 
     return 0;
}

引用和指针的不同点:

1. 引用概念上定义一个变量的别名,指针存储一个变量地址。

2. 引用在定义时必须初始化,指针没有要求

3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体

4. 没有NULL引用,但有NULL指针

5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32

位平台下占4个字节)

6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小

7. 有多级指针,但是没有多级引用

8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理

9. 引用比指针使用起来相对更安全

C++中可以用宏来定义函数

#define Add(x,y) ((x)+(y))

但是其会有优缺点

优点:没有类型的严格限制,不需要建立栈帧,提高效率

缺点:容易错误,语法坑很多,不能调试,没有类型安全的检查

进而,引出了一个新的关键字——incline

内联函数

概念

以inline修饰的函数叫做内联函数,编译时C++编译器会在调用内联函数的地方展开,没有函数调 用建立栈帧的开销,内联函数提升程序运行的效率。

inline int add(int x, int y)
{
	return x + y;
}

特性

1.inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会 用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运 行效率。

2.inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到。

// F.h

#include <iostream>

using namespace std;

inline void f(int i);

// F.cpp

#include "F.h"

void f(int i)
{
 cout << i << endl;
}

// main.cpp

#include "F.h"

int main()
{
 f(10);
 return 0;
}

// 链接错误:main.obj : error LNK2019: 无法解析的外部符号 "void __cdecl 
f(int)" (?f@@YAXH@Z),该符号在函数 _main 中被引用

auto关键字

1.根据右侧的变量,自动推导出类型

int main()
{
	int a = 0;
	auto b = a;//根据右边的类型,自动推导出左边的类型
	auto c = &a;//c就是指针,int*
	cout << typeid(c).name() << endl;
	auto& d = a;//d就是引用,引用a
	cout << typeid(d).name() << endl;
	//简化代码——简化复杂类型的定义
	//auto不能作为函数的参数,也不能直接用来声明函数
	std::vector<std::string> v;
	auto it = v.begin();
	cout << typeid(it).name() << endl;
	return 0;
}

但是auto不能作为函数的参数,也不可以直接用来声明函数

2.特殊的auto-for遍历

对于遍历一个数组,对于C语言中

int main()
{
	int array[] = { 1,2,3,4,5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
	{
		array[i] *= 2;
	}
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
	{
		cout<<array[i]<<" ";
	}
    return 0;
}

但是在C++中,可以这样子实现:

for (auto e : array)
{
	cout << e << " ";
}
cout << endl;

依次取数组的数据赋值给e,直到没有数据就会结束,会自动读取,自动迭代(++)

注意!!这个可以视为一个函数,从数组里读取数字然后打印,但若是想改变数组的数字,那么就需要用到别名来实现

for (auto x : array)
{  
	x *= 2;//此时无变化
}

for (auto& x : array)
{  
	x *= 2;//数组里的数字才会真正发生改变
}

但是在函数里,则不能使用——因为此用法只能用于有命名的,形参实际上不具有数组名

void TestFor(int array[])
{
	for (auto& e : array)//此时不行,因为形参没有数组名的概念,只能重新定义
		cout << e << endl;
}

不能用作函数的参数

// 此处代码编译失败,auto不能作为形参类型,因为编译器无法对a的实际类型进行推导

void TestAuto(auto a)
{}

不能直接声明数组

void TestAuto()
{
    int a[] = {1,2,3};
    auto b[] = {4,5,6};//err
}

使用

1. auto与指针和引用结合起来使用

用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须 加&

int main()
{
    int x = 10;
    auto a = &x;
    auto* b = &x;
    auto& c = x;
    cout << typeid(a).name() << endl;  
    cout << typeid(b).name() << endl;
    cout << typeid(c).name() << endl;
    *a = 20;
    *b = 30;
     c = 40;
    return 0;
}

 2.同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译 器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

void TestAuto()
{
    auto a = 1, b = 2; //pass
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

指针空值nullptr

在C语言中,NULL作为一个指针空值,但是在C++中NULL是个宏——定义为0或者被定义为无类型指针(void*)的常量。

所以若是想用NULL,则需要一个强制转换

void f(int)
{
     cout<<"f(int)"<<endl;
}

void f(int*)
{
     cout<<"f(int*)"<<endl;
}

int main()
{
     f(0);
     f(NULL);
     f((int*)NULL);
     return 0;
}

第二NULL个结果会按照0,作为整型去访问

因此为了避免麻烦,C++中将空指针定义为nullptr ——一个新的关键字

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nick-An

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值