您的位置:首页 > 编程语言 > C语言/C++

【七】C++一些新的关键字 -- new、delete、强制类型转换

2015-08-23 14:55 363 查看

目录

目录
1动态内存分配

2命名空间

3强制类型转换
C方式的强制类型转换

C强制类型转换
static_cast强制类型转换

const_cast强制类型转换

当volatile关键字作用于常量

reinterpret_cast强制类型转换

dynamic_cast强制类型转换

1、动态内存分配

C++中的动态内存分配已经和C语言有了明显区别:

C++中通过new关键字进行动态内存申请

C++中的动态内存申请是基于类型进行的

delete关键字用于内存释放

变量申请和释放:

Type* pointer = new Type;
// ……
delete pointer;


数组申请和释放:

Type* pointer = new Type
;
// ……
delete[] pointer;


new关键字与malloc函数的区别:

new关键字是C++的一部分,malloc是由C库提供的函数

new以具体类型为单位进行内存分配,malloc只能以字节为单位进行内存分配

new在申请单个类型变量时可进行初始化,malloc不具备内存初始化的特性

new对基本类型申请空间后默认初始化为0

对于类类型new和delete还负责构造函数和析构函数的调用

示例:

exp-1.cpp

#include <iostream>

using namespace std;

int main()
{
//申请数组,并默认初始化为0
int **p = new int*[10];
for(int i = 0; i < 10; i++)
{
cout << p[i] << '\t';
}
cout << endl;

//申请单个变量,并指定初始值
int *a = new int(5);
cout << "*a = " << *a << endl;

//申请单个变量,并默认初始化为0
double *d = new double;
cout << "*d = " << *d << endl;

delete [] p;
delete a;
delete d;

return 0;
}


运行结果:



2、命名空间

在C语言中只有一个全局作用域

C语言中所有的全局标识符共享同一个作用域

标识符之间可能发生冲突

C++中提出了命名空间的概念

命名空间将全局作用域分成不同的部分

不同命名空间中的标识符可以同名而不会发生冲突

命名空间可以相互嵌套

全局作用域也叫默认命名空间

C++命名空间的定义:

namespace name { /* … */ }


C++命名空间的使用:

使用整个命名空间:using namespace name;

使用命名空间中的变量:using name::variable;

使用默认命名空间中的变量:::variable;

默认情况下可以直接使用默认命名空间中的所有标识符:variable;

示例:

exp-2.cpp

#include <iostream>

using namespace std;

namespace First
{
int i = 0;
}

namespace Second
{
int i = 10;
namespace Internal
{
struct Student
{
const char *name;
int age;
};
}
}

int main()
{
using Second::Internal::Student;

First::i = 5;

Student stu;
stu.name = "Tom";
stu.age = First::i + Second::i;

cout << "Name:" << stu.name << "\n" << "Age:" << stu.age << endl;
return 0;
}


3、强制类型转换

C方式的强制类型转换:

( Type )( Expression )

Type( Expression )

示例:

exp-3.cpp

#include <stdio.h>

typedef void(PF) (int);

struct Point
{
int x;
int y;
};

int main()
{
//定义一个整数
int v = 0x12345;

//下面就开始乱来了!想怎么搞就怎么搞!
PF *pf = (PF*)v;
char c = char(v);

//我都不知道我在写什么....
pf(c);

Point *p = (Point*)v;

printf("Point::x = %d\n", p->x);
printf("Point::y = %d\n", p->y);
return 0;
}


上面的程序,编译能过,最多也就给个警告,但是运行肯定出错!

C方式强制类型转换存在的问题

过于粗暴

任意类型之间都可以进行转换,编译器很难判断其正确性

难于定位

在源码中无法快速定位所有使用强制类型转换的语句

如何进行更加安全可靠的转换呢?

C++强制类型转换

C++将强制类型转换分为4种不同的类型



static_cast强制类型转换

用于任何具有明确定义的类型之间的转换,只要不包含底层const,都可以使用!

const char *cp = “C++”; char *q = static_cast< char* >(cp);

上面这句就是错误的,static_cast不能去掉底层const

用于基本类型间的转换,但不能用于基本类型指针间的转换!

用于有继承关系类对象之间的转换和类指针之间的转换!

Tip:

  static_cast是编译期进行转换的,无法在运行时检测类型,所以类类型之间的转换可能存在风险。

示例:

exp-4.cpp

#include <iostream>
using namespace std;

int main()
{
int i = 97;
char c;

c = static_cast<char>(i);       //OK!
i = static_cast<int>(c);        //OK!

char *pa = static_cast<char*>(&i);  ////Error!!

cout << "char c = '" << c << "'"<<endl;
cout << "int i = " << i <<endl;

const char *cp = "C++";
char *q = static_cast< char* >(cp); //Error!!

return 0;
}


const_cast强制类型转换

用于去除变量的const属性!

只能改变运算对象的底层const!

示例:

exp-5.cpp

#include <stdio.h>

int main()
{
//这样声明,相当于得到了一个只读变量,而非常量
const int& j = 1; //相当于: int temp = 1; const int&j = temp;  //temp来自符号表

int& k = const_cast<int&>(j); //对j这个只读变量取引用,并强制去掉了它的const属性:const int* const ==> int* const,得到了一个别名为k的普通变量

k = 5;

printf("k = %d\n", k);  //普通变量,来自存储空间
printf("j = %d\n", j);  //只读变量,来自存储空间
printf("&k = %p\n", &k);
printf("&j = %p\n", &j);

//这里才是声明了一个常量,符号表中会有它
const int x = 2;
int& y = const_cast<int&>(x);
//这里对x这个常量取了引用,引用的本质是指针常量,所以导致编译器为常量x分配了存储空间
//然后,这里的const_cast相当于转换了:const int* const类型的指针为int *const类型
//而且,这里不能这些做:int& y = x; 会报错!!因为如果没有const_cast<int&>(x);那么x始终都还是一个常量,没有存储空间,不是只读变量!

y = 8;

printf("x = %d\n", x);  //这里用的是常量,来自符号表
printf("y = %d\n", y);  //这里用的是只读变量,来自存储空间
printf("&x = %p\n", &x);
printf("&y = %p\n", &y);

return 0;
}


运行结果:



Tip:

  关于以上程序运行结果的本质原因,在前面的文章中说过,请看这里

当volatile关键字作用于“常量”

volatile关键字,告诉编译器不做任何的优化,每次直接到内存中存取值!

volatile关键字的详细介绍,请看这里

思考?

  经过volatile关键字后,const int i = 1; 还是一个常量么?

验证方法:

  我们取i的地址并去掉它的底层const属性,假设它还是一个常量,那么通过指针修改i的内存值后,i的输出值不会改变,因为常量的值来自于符号表;如果值改变了,说明i已经成为了一个只读变量,它的值来自于存储空间!

示例:

exp-6.cpp

#include <stdio.h>

int main()
{
volatile const int i = 1;

int *p = const_cast<int*>(i);

*p = 100;

printf("i = %d\n", i);
printf("*p = %d\n", *p);

return 0;
}


运行结果:



Tip:

  从结果上表明,volatile 关键字作用于常量时,常量会变成只读变量,不再使用符号表,而直接使用编译器为“常量”分配的内存空间中的值!

reinterpret_cast强制类型转换

用于指针类型间的强制转换

用于整数和指针类型间的强制转换

通常为运算对象的位模式提供较低层次上的重新解释,直接复制二进制位来实现类型转换,是一种极其不安全的转换!

示例:

exp-6.cpp

#include <stdio.h>

int main()
{
int i = 0;
char c = 'c';
int* pi = &i;
char* pc = &c;

pc = reinterpret_cast<char*>(pi);
pi = reinterpret_cast<int*>(pc);

pi = reinterpret_cast<int*>(i);

c = reinterpret_cast<char>(i); // Error!

return 0;
}


dynamic_cast强制类型转换

主要用于类层次间的转换,还可以用于类之间的交叉转换

dynamic_cast具有类型检查的功能,比static_cast更安全
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: