AI智能
改变未来

C++学习笔记1-命名空间、const关键字的用法、new/delete表达式、引用、C++强制转换、bool和异常


1.命名空间

①来源:名字冲突就是在同一个作用域中有两个或多个同名的实体,为了解决命名冲突C++中引入了命名空间
②定义:命名空间又称为名字空间,是程序员命名的内存区域,程序员根据需要指定一些有名字的空间域,把一些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开。通俗的说,每个名字空间都是一个名字空间域,存放在名字空间域中的全局实体只在本空间域内有效
③作用:程序员根据需要指定一些有名字的空间域,把一些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开防止冲突

④命名空间的使用方式:using编译指令、作用域限定符、using声明机制。
using namespace std; -》》其中std代表的是标准命名空间
下面是直接使用会可能造成错误的情况
1)using编译指令

2)作用域限定符:直接使用作用域限定符::,每次要使用某个名称空间中的实体时,都直接加上

3)using声明机制
using声明机制的作用域:从using语句开始,到using所在的作用域结束。(要注意,在同一作用域内用using声明的不同的命名空间的成员不能有同名的成员,否则会发生重定义)

⑤匿名命名空间:其实匿名命名空间和static是同样的道理,都是只在本文件内有效,无法被其它文件引用

⑥命名空间的嵌套及覆盖

⑦ 对命名空间的思考和总结
1)提倡在已命名的名称空间中定义变量,而不是直接定义外部全局变量或者静态全局变量。
2)如果开发了一个函数库或者类库,提倡将其放在一个名称空间中
3)对于using 声明,首先将其作用域设置为局部而不是全局
4)不要在头文件中使用using编译指令,这样,使得可用名称变得模糊,容易出现二义性,
5)包含头文件的顺序可能会影响程序的行为,如果非要使用using编译指令,建议放在所有#include预编译指令后。
6)包含头文件的顺序可能会影响程序的行为,如果非要使用using编译指令,建议放在所有#include
预编译指令后。

2.const关键字的用法

  1. const关键字修饰变量

    除了这种方式可以创建常量外,还可以使用宏定义的方式创建常量
#defin20000e NUMBER 1024

问题:
常考题:const常量与宏定义的区别是什么?
1)编译器处理方式不同。宏定义是在预处理阶段展开,做字符串的替换;而const常量是在编译时。
2)类型和安全检查不同。宏定义没有类型,不做任何类型检查;const常量有具体的类型,在编译期会执行类型检查。在使用中,应尽量以const替换宏定义,可以减小犯错误的概率。
2. const关键字修饰指针

  1. const关键字修饰成员函数
  2. const关键字修饰对象

3.new/delete表达式

C中用来开辟和回收堆空间的方式是采用malloc/free库函数,在C++中提供了新的开辟和回收堆空间
的方式,即采用new/delete表达式。
1.开辟一个元素的空间

2.开辟一个数组的空间

常考题:new/delete表达式与malloc/free的区别是?
1)malloc/free是C/C++语言的标准库函数,new/delete是C++的运算符或表达式 ;
2)new能够自动分配空间大小,malloc需要传入参数;//new自动
3)new开辟空间的同时还对空间做了初始化的操作,而malloc不行;//new增加了对空间的初始化操作
4)new/delete能对对象进行构造和析构函数的调用,进而对内存进行更加详细的工作,而malloc/free不能。//new还能进行更多功能的调用
(既然new/delete的功能完全覆盖了malloc/free,为什么C++还保留malloc/free呢?因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。)

4.引用

1.什么是引用
在理解引用概念前,先回顾一下变量名。变量名实质就是一段连续内存空间的别名。那一段连续的内存空间只能取一个别名吗? 显然不是,引用的概念油然而生。在C++中,引用是一个已定义变量的别名。
其语法是:

在使用引用的过程中,要注意以下几点:

  1. &在这里不再是取地址符号,而是引用符号,相当于&有了第二种用法
  2. 引用的类型必须和其绑定的变量的类型相同
  3. 声明引用的同时,必须对引用进行初始化,如上的int &ref2;否则编译时报错
  4. 一旦绑定到某个变量之后,就不会再改变其指向

2.引用的本质
①C++中的引用本质上是一种被限制的指针。
②由于引用是被限制的指针,所以引用是占据内存的,占据的大小就是一个指针的大小。有很多的说法,都说引用不会占据存储空间,其只是一个变量的别名,但这种说法并不准确。引用变量会占据存储空间,存放的是一个地址,但是编译器阻止对它本身的任何访问,从一而终总是指向初始的目标单元。在汇编里, 引用的本质就是“间接寻址”。在后面学习了类之后,我们也能看到相关的用法。
3.引用作为函数参数
①引用的作用:在很多场合下就可以用引用代替指针,因而也具有更好的可读性和实用性。这就是引用存在的意义

②参数传递的方式除了上面的指针传递和引用传递两种外,还有值传递。采用值传递时,系统会在内存中
开辟空间用来存储形参变量,并将实参变量的值拷贝给形参变量,即形参变量只是实参变量的副本而已;注意如果函数传递的是类对象,系统还会调用类中的拷贝构造函数来构造形参对象,假如对象占据的存储空间比较大,那就很不划算了。这种情况下,强烈建议使用引用作为函数的形参,这样会大大提高函
数的时空效率。

4.引用作为函数的返回值
当引用作为函数的返回值时,必须遵守以下规则:
5. 不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
6. 不能在函数内部返回new分配的堆空间变量的引用。如果返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么该引用所在的空间就无法释放,会造成内存泄漏。

引用总结:
7. 在引用的使用中,单纯给某个变量取个别名是毫无意义的,引用的目的主要用于在函数参数传递
中,解决大块数据或对象的传递效率和空间不如意的问题。
8. 用引用传递函数的参数,能保证参数传递中不产生副本,提高传递的效率,且通过const的使用,
保证了引用传递的安全性。
9. 引用与指针的区别是,指针通过某个指针变量指向一个变量后,对它所指向的变量间接操作。程序中使用指针,程序的可读性差;而引用本身就是目标变量的别名,对引用的操作就是对目标变量的操作。

5.C++强制转换

1)c++为了克服这些缺点:①c风格的转换不容易查找,它由一个括号加上一个标识符组成,而这样的东西在c++程序里一大堆;②把一个指向const对象的指针转换成指向非const对象的指针,把一个指向基类对象的指针转换成指向一个派生类对象的指针,这两种转换之间的差别是巨大的,但是传统的c语言风格的类型转换没有区分这些
2)
①static_cast
最常用的类型转换符,在正常状况下的类型转换, 用于将一种数据类型转换成另一种数据类型,如把int转换为float

也可以完成指针之间的转换,例如可以将void*指针转换成其他类型的指针

但不能完成任意两个指针类型间的转换

总结,static_cast的用法主要有以下几种:
1)用于基本数据类型之间的转换,如把int转成char,把int转成enum。这种转换的安全性也要开发人
员来保证。
2)把void指针转换成目标类型的指针,但不安全。
3)把任何类型的表达式转换成void类型。
4)用于类层次结构中基类和派生类之间指针或引用的转换。进行上行转换(把派生类的指针或引用转换
成基类指针或引用)是安全的;进行下行转换(把基类指针或引用转换成派生类指针或引用)时,由于没有动态类型检查,所以是不安全的。
2.const_cast
该运算符用来修改类型的const属性。常量指针被转化成非常量指针,并且仍然指向原来的对象;常量引用被转换成非常量引用,并且仍然指向原来的对象;常量对象被转换成非常量对象。
3. dynamic_cast
该运算符主要用于基类和派生类间的转换,尤其是向下转型的用法中。
4. reinterpret_cast
该运算符可以用来处理无关类型之间的转换,即用在任意指针(或引用)类型之间的转换,以及指针与足够大的整数类型之间的转换。由此可以看出,reinterpret_cast的效果很强大,但错误的使用reinterpret_cast很容易导致程序的不安全,只有将转换后的类型值转换回到其原始类型,这样才是正确
使用reinterpret_cast方式。

6、函数重载

在实际开发中,有时候需要实现几个功能类似的函数,只是细节有所不同。如交换两个变量的值,但这两种变量可以有多种类型,short, int, float等。在C语言中,必须要设计出不同名的函数,其原型类似于:

7、默认参数

C++可以给函数定义默认参数值。通常,调用函数时,要为函数的每个参数给定对应的实参,

如果一个函数中有多个默认参数,则形参分布中,默认参数应从右至左逐渐定义。当调用函数时,只能向左匹配参数。如

默认参数与函数重载,默认参数可将一系列简单的重载函数合成为一个。例如:

如果一组重载函数(可能带有默认参数)都允许相同实参个数的调用,将会引起调用的二义性。

8.bool类型

在C++中,还添加了一种基本类型,就是bool类型,用来表示true和false。true和false是字面值,可以通过转换变为int类型,true为1,false为0.

任何数字或指针值都可以隐式转换为bool值。
任何非零值都将转换为true,而零值转换为false.

9.inline函数
内联函数作为编译器优化手段的一种技术,在降低运行时间上非常有用
1.什么是内联函数?
用来降低程序的运行时间。当内联函数收到编译器的指示时,即可发生内联:编译器将使用函数的定义体来替代函数调用语句,这种替代行为发生在编译阶段而非程序运行阶段。
(定义函数时,在函数的最前面以关键字“inline”声明函数,即可使函数称为内联声明函数。)

2. 内联函数和带参数的宏定义
1.使用宏代码的缺点:
①容易出错,预处理器在拷贝代码时经常产生想不到的边际效应
②不可调试,但是内联函数可以调试
③无法操作类的私有数据成员
④优点:可以通过上下文相关的优化技术对结果代码进行更深入的优化
3.谨慎使用内联函数

10.异常安全
异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw。

①throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。

②try: try 块中的代码标识将被激活的特定异常,它后面通常跟着一个或多个 catch 块。
理论:

举例:

③catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。

额外补充:
cin相当于scanf输入数据
endl表示加个回车
cout,标准输出,相当于printf
这个>>输入流运算符
而<<,输出流运算符

#include <stdio.h>#include <iostream>//C++头文件没有加.h,因为C++头文件都是用模板写的,//而模板有个特点:必须要知道所有实现之后才能正常编译using namespace std;//命名空间//函数的声明//函数声明可以有多次,函数定义只能有一次void test();void test();void test();void test();void test();void test(){}int main(int argc, char **argv){/* &10;//error,字面值常量,不能取地址 *//* &"Hello, world";//ok *///cout,标准输出//<<,输出流运算符//"Hello world",字符串常量//endl end of linecout << "Hello world" << endl;operator<<(cout, "Hello world").operator<<(endl);//运算符重载int number = 0;//cin,标准输入//>>,输入流运算符cin >> number;cout << "number = " << number << endl;return 0;}
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » C++学习笔记1-命名空间、const关键字的用法、new/delete表达式、引用、C++强制转换、bool和异常