C++关键字
C++关键字
static
类和结构体外的static
被static修饰后只在内部发生链接,其作用域只在其所在的文件中。
类和结构体内的static
struct Entity { static int x, y; 静态成员变量 static void Print() { std::cout << x << "," << y << std::endl; } }; int Entity::x; //类中的静态变量需单独声明 int Entity::y;
静态成员变量:
若static修饰变量,在所有类的实例中,此静态成员变量只有一个实例,改变某个实例中的静态变量,所有实例中的此变量都会改变,因为所有实例中的静态变量指向同一个内存。
因此改变类中静态变量只需:Entity::x = 1; Entity::y = 0;
在编译阶段分配内存。
类中的静态变量需在类外单独声明或初始化。
静态成员函数:
若static修饰函数,静态函数只能访问静态变量,静态方法没有类实例。
static void function(){}
局部静态
生命周期:整个程序
作用域:局部作用域
Const
C++中的const分为顶层const和底层const,在进行拷贝操作的时候,可以将顶层const忽略,底层则不行。
Const修饰变量
- 普通变量的const:表示变量的值不可改变,由于该const为一个顶层,可将其赋值给一个int类型的变量,不会报错。
const int a = 2;
//a = 10; // Error const修饰变量后变量不可改变
int b = a; // Right
-
**指针的const: **
-
常量指针:const修饰指针所指向的变量,即指针指向的内容不可改变,该const是一个底层const,也就是说不可将其赋值给一个int*类型的变量,同时const修饰符放在类型前和类型后都表示修饰类型。
const int* p = &a; // const int* p == int const* p //*p = 8; // Error 指针指向的内容不可改变 //int* p0 = p; // Error 拷贝操作不可忽略底层const
-
指针常量:const修饰指针本身,指针的指向不可改变,该const是一个顶层const。
int* const p = &a; //p1 = &c; //指针的指向不可改变 int* p0 = p; // Right 拷贝操作可忽略顶层const
-
指向的内容和指向都不能改变。
const int* const p = &a; const int* p0 = p; // Right 拷贝操作可忽略顶层const //int* const p1 = p; //Error 拷贝操作不可忽略底层const //int* p2 = p; // Error
-
其实说那么多顶层const底层const,const的本质还是限定被修饰的变量不能被改变,也就是说注意const修饰的是谁即可。例如像是上面的例子中发生拷贝操作时,常量指针被赋值给普通指针会报错,可理解为由于常量指针只为了保证指向的内容不可改变,所以若是能够复制给普通指针,那么const本身就没有意义了,所以该操作被禁止。
Const修饰函数
-
常函数(只可在类中使用):const修饰后表示不会修改调用该方法的对象的任何实际的变量。
-
常函数内不可以修改成员属性。
-
成员属性声明时加关键字mutable后,在常函数中依然可以修改
class Entity { private: mutable int m_X; int m_Y; public: int GetX() const //表明该方法不会修改调用该方法的对象的任何实际的变量 { m_X = 3; //const修饰后不可改变,mutable修饰的变量除外 return m_X; } };
-
const不能修饰static修饰的静态成员方法。
-
-
包含常函数的常对象:
-
常对象只能调用常函数。
const Entity e;
-
当成员函数的 const 和 non-const 版本同时存在时,const 对象只会调用 const 版本,non-const 对象只会调用 non-const 版本。
mutable
const修饰的方法可修改mutable修饰的变量。
动态内存new和delete
new
new关键字在堆上创建内存并调用构造函数。
//两者的区别仅是new关键字还会调用构造函数 Entity* e1 = new Entity(); Entity* e2 = (Entity*)malloc(sizeof(Entity));
若使用new[]来分配数组,需使用delete[]。
int* b = new int[10]; delete[] b;
placement new:
new (address) (type) initializer
placement new可以让对象在已知地址完成构造。
m_Data = static_cast<T*>(::operator new(sizeof(T) * size)); new(m_Data + m_Size) T(value); //在m_Data + m_Size的位置上构造一个T(value)
delete只能删除堆中分配的内存,所以placement new不能使用delete删除内存。
可使用析构函数辅助删除。
m_Data[i].~T();
delete
- delete关键字在堆上删除内存并调用析构函数。
explicit
取消隐式转换,要求显式的调用构造函数。
auto
编译器自动转换成需要的类型。
constexpr
指示编译器在编译时计算表达式的值,并将其视为常量,可减小运行时的计算开销,提高程序的性能。
异常处理throw,try和catch
- throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
- catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
- try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
语法:
try{
// 保护代码
}
catch( ExceptionName e1 ){
// catch 块
}
catch( ExceptionName eN ){
// catch 块
}
如果 try 块在不同的情境下会抛出不同的异常,这个时候可以尝试罗列多个 catch 语句,用于捕获不同类型的异常。
抛出异常
throw 语句的操作数可以是任意的表达式,表达式的结果的类型决定了抛出的异常的类型。如:
throw "Division by zero condition!"; //抛出const char*类型的异常
throw std::out_of_range("out of range"); //抛出std::out_of_range类型的异常
捕获异常
catch 块跟在 try 块后面,用于捕获异常。可以指定想要捕捉的异常类型,这是由 catch 关键字后的括号内的异常声明决定的。
try{
// 保护代码
}
catch( ExceptionName e ){
// 处理 ExceptionName 异常的代码
}
catch( ... ) //若想处理任何种类的异常,可使用(...)
C++ 标准的异常
C++ 提供了一系列标准的异常,定义在
下表是对上面层次结构中出现的每个异常的说明:
除了使用C++标准异常,还可通过继承和重载std::exception类来自定义异常。