游戏开发之C++对C的扩展(C++)
1.C++的输入和输出
??头文件为iostream,扩展为in out stream,即输入输出流。
std::endl;
std::cout<<"hello world"<<std::endl;
2.命名空间
2.1 域作用符
主要有以下两点作用
- 配合命名空间一起使用
- 用户访问相同变量名的全局变量时,可以屏蔽当前作用域的变量名
- 可优先识别命名空间外部的函数(需要取消命名空间,让命名空间内部函数名相同的暴露)
using namespace A;
namespace A
{
void Print()
{
std::cout << " 命名空间内部print " << std::endl;
}
}
void Print()
{
std::cout << " 自定义print " << std::endl;
}
int a = 20;
int main()
{
int a =100;
std::cout<< a << std::endl;
std::cout << ::a << std::endl;
::Print();
A::Print();
return 0;
}
2.2 C++名字空间
??在c++中,名称(name)可以是符号常量名、变量名、函数名、结构体变量名、枚举类型名、类名和对象名称等等。为了避免名称的冲突(标识符)C++引入命名空间(namespace)。命名空间是为了避免变量名冲突的解决方案。
2.3 命名空间的使用
- 声明
namespace [空间名称] { 定义变量 函数 数据类型 结构体 类 。。。。。。【代码段】 } //namespace属于关键字。
- 访问
空间名称::成员变量名; 空间名称::成员名称;
namespace [空间名称]{
代码段
}
namespace A
{
int a =10;
}
namespace B
{
int a = 20;
}
int main()
{
std::cout << A::a << std::endl;
std::cout << B::a << std::endl;
return 0;
}
2.3.1 命名空间不能嵌套在函数内部
错误写法:
int main()
{
namespace A
{
int a =10;
}
namespace B
{
int a = 20;
}
std::cout << A::a << std::endl;
std::cout << B::a << std::endl;
return 0;
}
2.3.2 命名空间可以相互嵌套
namespace A
{
int a = 10;
namespace C
{
int a;
}
}
namespace B
{
int a = 10;
namespace C
{
int a;
}
}
2.3.3 命名空间可以随时添加扩展
??可以随时把新成员添加进入,不是一定义好便不可更改。
namespace B
{
int a = 10;
namespace C
{
int a;
}
}
namespace B
{
namespace D
{
int a;
}
void Print()
{
std::cout << "namespace B" << std::endl;
}
}
2.3.4 命名空间可以分离声明和定义
namespace A
{
void Print();
}
void A::Print()
{
std::cout << "namespace A" << std::endl;
}
2.3.5 匿名命名空间
??作用跟static类似,只能在本文件中生效。
namespace
{
void Print()
{
std::cout << " " << std::endl;
}
}
namespace
{
void Print1()
{
std::cout << " 匿名命名空间1 " << std::endl;
}
}
2.4 命名空间的取消
TIPS:一定不要随意取消命名空间,因为取消意味着暴露。例如自己定义了一个函数名,一个命名空间暴露了一个函数名与自己定义的相同可能造成不必要的bug。
2.4.1 暴露命名空间的某个变量
using 域名称::描述符;// 声明域中的某一个变量暴露出来 即using 空间名称::变量名或函数名或结构体名称等等;
using A::a;
2.4.2 暴露整个命名空间
using namespace 域名称;// 声明一个命名空间暴露整个空间
using namespace A;
3.严格的类型转换(C++类型转换的增强)
typedef enum
{
red, blue
}COLOR;
int main(int argc, char** argv)
{
COLOR color = red;
color = 1;
int* p = malloc(10);
char* str = "张三";
return 0;
}
3.1 数据类型转换的增强
C++中类型转换需要显示声明,比如 void 转 int 需要显示调用(int*) volatile关键字解析,保持内存可见性(CPU每次处理这个被volatile修饰的变量的时候,都会从内存中重新加载变量的值到寄存器)
- static_cast
用于非多态类型转换(静态转换),任何标准转换都可以使用它,但是不能用于两个完全不相关的类型转换。static_cast转换的时候会进行安全检测,检测两个类型是否为相关类型。
int i = 10;
double b = static_cast<double>(i);
const char* str = "张三";
int a = static_cast<int>(str);
- reinterpret_cast
将一种类型转换为另一种不同的类型,就是C中的强制类型转换。
int i = 20;
int* b = reinterpret_cast<int*>(i);
std::cout << i << " " << b << std::endl;
- const_cast
删除变量const的属性,方便赋值。
const int i = 3;
int* p = const_cast<int*>(&i);
*p = 3;
std::cout << p << " " << i << std::endl;
- dynam_cast
用于将一个父类对象的指针转换为子类对象的指针或引用。(动态交换)必需包含一个多态类型(虚函数)。
class A { int a; virtual void func() {} };
class B : public A { int b; };
class C :public A { int c; };
int main()
{
B b;
A* a = dynamic_cast<B*>(&b);
if (nullptr == a)
printf("error\n");
else
printf("success\n");
C* c = dynamic_cast<C*>(a);
if (nullptr == c)
printf("error\n");
else
printf("success\n");
return 0;
}
4.结构体的增强
- 在C++中,使用结构体不需要添加struct关键字
struct tempA
{
int tempa;
};
int main()
{
tempA num;
return 0;
}
- 在C++中,结构体可以有成员变量和成员函数
typedef struct tagA
{
int a;
void Print()
{
std::cout << "Hello " << a << std::endl;
}
}TA, * PTA;
- 在C++中,结构体可以进行继承
struct A
{
int a;
void SetA(int a_)
{
a = a_;
}
};
struct B : A
{
int b;
void SetB(int b_)
{
b = b_;
}
};
int main()
{
A a;
a.SetA(100);
printf("%d\n", a.a);
B b;
b.SetA(300);
b.SetB(200);
printf("%d %d\n", b.a, b.b);
return 0;
}
5.const的增强
- 在C中const是一个只读的变量,而在C++中是一个常量,可以当作数组长度使用。
- C++中const声明的变量没有占用内存,而在C中const需要申请内存。
- 在C++中尽可能使用const代替宏。
在C++中,常量在编译期间会进行类似于宏替换的操作。 如果对一个常量取地址(或之后对其进行改写),会生成一个临时的内存空间,这个内存空间不会指向该常量。
int main()
{
const int *p;
int *const p = (int*)malloc(10);
const int N = 200;
int nums[N];
int* p = (int*)&N;
*p = 500;
printf("%d\n", N);
return 0;
}
|