文章目录
C++中的动态内存分配
C++中通过new关键字进行动态内存申请
C++中的动态内存申请是基于类型进行的
delete关键字用于内存释放
//变量申请
Type* pointer = new Type;
delete pointer;
//数组申请
Type* pointer = new Type[N];
delete[] pointer;
#include <stdio.h>
int main()
{
//单个
int* p = new int;
*p = 5;
*p = *p + 10;
printf("p = %p\n", p);
printf("*p = %d\n", *p);
delete p;
p = NULL;
//数组
p = new int[10];
for(int i=0; i<10; i++)
{
p[i] = i + 1;
printf("p[%d] = %d\n", i, p[i]);
}
delete[] p; //注意:delete p 会造成内存泄漏
p = NULL;
printf("Press any key to continue...");
getchar();
return 0;
}
new和malloc的区别
new关键字与malloc函数的区别
new关键字是C++的一部分,malloc是由C库提供的函数
new以具体类型为单位进行内存分配,malloc只能以字节为单位进行内存分配
new在申请单个类型变量时可进行初始化,malloc不具备内存初始化的特性
#include <stdio.h>
int main()
{
int* pi = new int(1);
float* pf = new float(2.0f);
char* pc = new char('c');
printf("*pi = %d\n", *pi);
printf("*pf = %f\n", *pf);
printf("*pc = %c\n", *pc);
delete pi;
pi = NULL;
delete pf;
pf = NULL;
delete pc;
pc = NULL;
printf("Press any key to continue...");
getchar();
return 0;
}
C++中的命名空间
在C语言中只有一个全局作用域
C语言中所有的全局标识符共享同一个作用域
标识符之间可能发生冲突
C++中提出了命名空间的概念
命名空间将全局作用域分成不同的部分
不同命名空间中的标识符可以同名而不会发生冲突
命名空间可以相互嵌套
全局作用域也叫默认命名空间
#include <stdio.h>
namespace First
{
int i = 0;
}
namespace Second
{
int i = 1;
namespace Internal
{
struct P
{
int x;
int y;
};
}
}
int main()
{
printf("Press any key to continue...");
getchar();
return 0;
}
使用命名空间
#include <stdio.h>
namespace First
{
int i = 0;
}
namespace Second
{
int i = 1;
namespace Internal
{
struct P
{
int x;
int y;
};
}
}
int main()
{
using namespace First;
using Second::Internal::P;
printf("i = %d\n", i);
printf("i = %d\n", Second::i);
P p = {2, 3};
printf("p.x = %d\n", p.x);
printf("p.y = %d\n", p.y);
printf("Press any key to continue...");
getchar();
return 0;
}
C++命名空间的使用:
使用整个命名空间:using namespace name;
使用命名空间中的变量:using name::variable;
使用默认命名空间中的变量:::variable
tips:
默认情况下可以直接使用默认命名空间中的所有标识符。
强制类型转换
C语言中的强制类型转换
#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(v);
Point* p = (Point*)v;
printf("p->x = %d\n", p->x);
printf("p->y = %d\n", p->y);
printf("Press any key to continue...");
getchar();
return 0;
}
运行结果:
分析:C语言中的强制类型转换过于灵活/粗暴,存在问题!
C语言方式强制类型转换存在的问题
C方式强制类型转换存在的问题
过于粗暴
任意类型之间都可以进行转换,编译器很难判断其正确性
难于定位
在源码中无法快速定位所有使用强制类型转换的语句
tips:
在程序设计理论中强制类型转换是不被推荐的,与goto语句一样,应该尽量避免。
C++中的强制类型转换
C++将强制类型转换分为4种不同的类型
static_cast
const_cast
dynamic_cast
reinterpret_cast
用法:xxx_cast< Type >( Expression )
static_cast
static_cast强制类型转换
用于基本类型间的转换,但不能用于基本类型指针间的转换
用于有继承关系类对象之间的转换和类指针之间的转换
#include <stdio.h>
int main()
{
int i = 0x12345;
char c = 'c';
int* pi = &i;
char* pc = &c;
c = static_cast<char>(i); //用于基本类型间的转换
pc = static_cast<char*>(pi); //ERROR 不能用于基本类型指针间的转换
}
//复习时添加
#include <stdio.h>
#include <string.h>
class Parent{
};
class Child : public Parent{
public:
int m_iA;
};
int main(int argc, char *argv[])
{
//类对象
Parent p;
Child c;
p = static_cast<Parent>(c);
// p = c; //赋值兼容性原则:子类是特殊的父类
//类指针
Parent* pp;
Child* pc;
pp = static_cast<Parent*>(pc);
return 0;
}
tips:
static_cast是编译期进行转换的,无法在运行时检测类型,所以类类型之间的转换可能存在风险。
const_cast
#include <stdio.h>
int main()
{
const int& j = 1; //得到一个只读变量
int& k = const_cast<int&>(j); //去掉const属性,成为普通变量
const int x = 2; //真正意义上的常量
int& y = const_cast<int&>(x); //对x取引用,引用实质上是常指针,相当于取地址,会给x分配内存空间;
//引用y 指的是 x的内存空间 的别名;
k = 5;
printf("k = %d\n", k);
printf("j = %d\n", j);
y = 8;
printf("x = %d\n", x); //直接从符号表中取
printf("y = %d\n", y);
printf("&x = %p\n", &x);
printf("&y = %p\n", &y); //x和y的地址一样
}
const_cast强制类型转换
用于去除变量的const属性
reinterpret_cast
reinterpret_cast强制类型转换
用于指针类型间的强制转换
用于整数和指针类型间的强制转换
#include <stdio.h>
typedef void(PF)(int);
int main()
{
int i = 0;
char c = 'c';
int* pi = &i;
char* pc = &c;
pc = reinterpret_cast<char*>(pi);
pi = reinterpret_cast<int*>(pc);
PF* pf = reinterpret_cast<PF*>(0x12345);
// c = reinterpret_cast<char>(i); // Oops! should be static_cast
printf("Press any key to continue...");
getchar();
return 0;
}
tips:
reinterpret_cast直接从二进制位进行复制,是一种极其不安全的转换。
dynamic_cast
dynamic_cast强制类型转换
主要用于类层次间的转换,还可以用于类之间的交叉转换(相同基类不同子类之间的交叉转换。但结果是NULL)
dynamic_cast具有类型检查的功能,比static_cast更安全
//复习添加:动态类型识别
#include <iostream>
using namespace std;
class Parent{
public:
virtual ~Parent(){ //dynamic_cast要求使用的目标对象类型是多态的
}
};
class Child : public Parent {
public:
int add(int a, int b);
};
class NewChild : public Parent{
};
int main()
{
Parent p;
Child c;
NewChild n;
//Parent类
Parent* pA;
pA = &p;
if(dynamic_cast<Child*>(pA)){ //父类 转化为 子类, 转换失败,返回NULL
cout<<"Dynamic Type: "<<"Parent"<<endl;
}
else{
cout << "Parent error"<<endl;
}
//Child类
Parent* pB;
pB = &c; //赋值兼容性原则
if(dynamic_cast<Child*>(pB)){ //dynamic_cast用于指针转换时,转换失败返回空指针
cout<<"Dynamic Type: "<<"Child"<<endl;
}
else{
cout << "Child error"<<endl;
}
//NewChild类
Parent* pC;
pC = &n;
if(dynamic_cast<NewChild*>(pC)){
cout<<"Dynamic Type: "<<"NewChild"<<endl;
}
else{
cout << "NewChild error"<<endl;
}
return 0;
}