C++入门_二

C++入门_二

在C++编程中,命名空间、输入/输出和缺省参数是三个非常重要的概念。它们分别帮助我们组织代码、与程序进行交互以及为函数提供默认值。下面,我们将逐一探讨这些概念。

一. 命名空间(namespace)

在C++中,随着代码量的增加,变量、函数和类的数量也会不断增加。如果它们都位于全局作用域中,很容易发生命名冲突。为了避免这种情况,C++引入了命名空间的概念。

命名空间允许我们将相关的标识符组织在一起,并为它们提供一个唯一的名称。这样,即使不同的库或代码片段使用了相同的标识符名称,我们也可以通过指定命名空间来明确区分它们。

例如,我们可以定义一个名为bit的命名空间,并在其中定义一些变量和函数:

namespace bit {  
    int num = 50;  
    void print() {  
        cout << num << endl;  
    }  
}

要使用命名空间中的成员,我们可以使用作用域解析运算符:: 例如:

cout << bit::num << endl;  
bit::print(![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=data%3Aimage%2Fgif%3Bbase64%2CR0lGODlhAQABAPABAP%2F%2F%2FwAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw%3D%3D&pos_id=img-vuO4Q5cJ-1715345712673)

另外,我们还可以使用`using`关键字来简化对命名空间成员的访问。例如:

```cpp
using bit::num;  
using bit::print;  
  
int main() {  
    cout << num << endl;  
    print();  
    return 0;  
}

使用using namesapace 可能会导致命名冲突和代码可读性下降,使用需谨慎!!!

二. C++的输入/输出操作

C++提供了coutcin是最常用的输出和输入流对象。

要使用 cout he cin 需要使用头文件 ,并且引用 std 命名空或者使用 std::

#include <iostream>  
using namespace std;  
  
int main() {  
    cout << "Hello, World!" << endl;  
    int number;  
    cin >> number;  
    cout << number << endl;  
    return 0;  
}

endl 是一个操纵符,它插入换行符。

三、缺省参数

缺省参数允许我们在定义函数时为参数提供默认值。这样,在调用函数时,如果省略了某些参数,它们将使用这些默认值。

缺省参数可以分为全缺省参数和半缺省参数。全缺省参数意味着所有参数都有默认值,而半缺省参数则意味着只有部分参数有默认值。

全缺省参数:

void Fun1(int num1 = 30, int num2 = 20, int num3 = 10)
{
	cout << num1 << endl;
	cout << num2 << endl;
	cout << num3 << endl;
}
int main()
{
	Fun1(1,2,3);
	// 1,2,3
	Fun2(1);
	// 1,20,10
	return 0;
}

我们可以选择提供所有参数、部分参数或不提供任何参数,函数将使用相应的默认值。

半缺省参数则要求从右到左依次给出默认值,中间不能间隔。例如:

void Fun2(int num1, int num2 = 20, int num3 = 30)
{
	cout << num1 << endl;
	cout << num2 << endl;
	cout << num3 << endl;
}
int main()
{
	Fun2(3);
	return 0;
}

上面的函数num1 需要提供默认值。其他有默认值。

需要注意的是,缺省参数不能在函数声明和定义中同时出现。

内联函数

概念

在c++中有一些需要经常使用的函数add,swap这些

此时有了一个叫内联函数

对函数进行展开

inline int Add(int a, int b)
{
	return a + b;
}
int main()
{
	int c = Add(6 , 7);
	cout << c << endl;
	return 0;
}

就像这样使用

 int c = Add(6 , 7);
 mov         edx,7  
 mov         ecx,6  
 call        Add (07FF6E76414A1h)  
 mov         dword ptr [c],eax  

但是我们看到仍然使用的是Add函数,因为调用了add函数的地址

为什么呢

因为在debug版本下不会展开的,目的方便调试

解决方法在在release模式下,查看编译器生成的汇编代码中是否存在call Add

特性
  1. inline是一种以空间换时间的做法,如果编译器按照内联函数处理,编译期间,会将函数体替换函数调用

有利亦有弊,缺点就是会让文件变大,优点效率更高。

  1. inline对于编译器而言只是一个建议不同编译器关于inline实现机制可能不同,一般建

议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、

是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性

  1. inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到了
// F.h
#include <iostream>
using namespace std;
//  展开之后,没有函数地址W
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;
}

auto关键字

干什么的

在我们写入的程序越来越多,程序中的类型也越来越复杂,亦如:

1.类型难于拼写

2.含义不明确导致容易出错

#include <string>
#include <map>
int main()
{
 std::map<std::string, std::string> m;
 std::map<std::string, std::string>::iterator it = m.begin();
 // 就像是这样的代码 可以使用 auto
 auto it = m.begin();

 return 0;
}

auto 可以自动推导变量类型

int a = 10;
auto b = 10;
auto c = 0;

cout << typeid(b).name() << endl;
cout << typeid(c).name() << endl;
// int int 
// 上面函数输出变量类型

注意:使用auto定义变量必须对其进行初始化,在编译阶段编译器需要根据初始化表达式推到auto的实际类型

因此auto并非是一种“类型”的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量实际的类型

怎么用的

1.auto可以与指针结合起来使用

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

int x = 10;
auto a = &x;
auto* b = &x;
auto& c = x;

2.在同一行定义多个变量

当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译

器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量

auto a = 1,b = 2;
auto c = 3;d = 4.5; // 该行会报错,因为c和d的初始化表达式类型不同
auto 不能使用的场景

1.auto不能作为函数的参数

// auto不能作为形参类型,因为编译器无法对a的实际类型进行推导
int swap (auto num)
{
  // ...
}

2.auto不能直接用来声明数组

int a[] = {1,2,3};
auto b[] = {1,1,1};

基于范围的for循环(C++11)

在c++98中如果要遍历一个数组,可以按照一下方式进行

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

此时我们也可以使用我们之前的auto加上for组合,让循环更加简洁

int array[] = { 1,2,3,4,5 };
for (auto&  e : array)
{
	e *= 2;
}
for (auto e : array)
{
	cout << e << endl;
}

使用auto条件

首先for循环的范围是确定的

指针空值nullptr(C++11)

在C语言中NULL实际是一个宏

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

可以看到NULL可能被定义为字面常量0,或者被定义为无类型指针(void*)的常量。

这样让我们在使用时会遇到一些麻烦

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;
}

程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。

在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。

在C++中出现了一个另一个表示NULL的nullptr

1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。

2. 在C++11中,sizeof(nullptr) 与 sizeof((void*)0)所占的字节数相同。

3.为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。


程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。

在C++98中,字面常量0既可以是一个整形数字,也可以是无类型的指针(void*)常量,但是编译器默认情况下将其看成是一个整形常量,如果要将其按照指针方式来使用,必须对其进行强转(void *)0。



**在C++中出现了一个另一个表示NULL的nullptr**

**1. 在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是C++11作为新关键字引入的。**

**2. 在C++11中,sizeof(nullptr) 与 sizeof((void\*)0)所占的字节数相同。**

**3.为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。**
  • 19
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值