static 关键字
C++中static关键字可以用于函数、变量和类中。它的作用不同,具体如下:
1. 函数中的static关键字:
当函数的返回值为static时,将该函数称为静态函数。该函数只能在当前文件中访问,不能在其他文件中被使用,因此它隐藏了自己的实现,是一种增强代码模块化的方式。同时,该函数也不需要再被链接器进行链接。
2. 变量中的static关键字:
当变量的声明时加上static关键字,则该变量为静态变量。静态变量位于全局数据区,其生命周期与程序的生命周期相同,即只会在程序进程中被构造一次,然后一直存在,且在程序结束后才在内存中被释放。
3. 类中的static关键字:
当类中的数据成员和成员函数加上static关键字时,称它们为静态数据成员和静态成员函数。
静态数据成员类似于类中的全局变量,它们在程序起始时被构造,在程序结束时才释放。每个类只有一份静态数据成员,被整个类共享,可以被类内的任意函数或成员访问。
静态成员函数是只与类相关,与具体的对象无关的函数。静态成员函数没有this指针,无法访问类的非静态成员和非静态函数,它只能访问静态成员和静态函数。它们的调用方式既可以使用对象名调用,也可以使用类名调用,但推荐使用类名调用,可以提高效率。
总之,static关键字可以帮助程序员更好地封装类和函数,同时提高程序的安全性和效率。
const 关键字
C++ const关键字用于定义不可变的数据,即常量。const可以用于变量、函数参数、函数返回值和类成员函数。
1.变量:用于声明一个不可变的值,一旦初始化就不能再更改它的值。
例如:
const int a = 5;
2.函数参数:
函数参数也可以用const来声明它不会被修改。这可以告诉编译器在函数执行期间禁止修改参数的值。
例如:
void foo(const int a) {
// do something
}
3.函数返回值:
const关键字也可以用于函数返回值,表示返回的值是只读的。
例如:
const int foo() {
return 5;
}
4.类成员函数:
const关键字可以用于类成员函数,表示这个函数不会修改类的状态,即不会修改类内的成员变量。
例如:
class MyClass {
public:
void print() const {
// do something
}
private:
int a;
};
这个print函数就是一个只读函数。
explicit 关键字
在C++中,explicit关键字用于标记构造函数,表示该构造函数不能用于隐式转换。当构造函数被声明为explicit时,它只能被显式调用构造对象,而不能通过隐式调用自动进行类型转换。
下面是一个例子,假设我们有一个Animal类和一个Cat类,Cat类从Animal类继承。如果我们只定义了Animal类的有参构造函数,并使用其隐式转换来创建一个Cat实例,则可以通过使用explicit关键字来防止这种情况:
class Animal {
public:
// 带一个参数的构造函数
Animal(int numLegs) : m_numLegs(numLegs){}
int getNumLegs() const { return m_numLegs; }
private:
int m_numLegs;
};
class Cat : public Animal {
public:
// 带一个参数的构造函数
explicit Cat(int numLegs) : Animal(numLegs){}
};
int main() {
Animal a = 4; // 正常编译通过,构造了一个动物,有4条腿
Cat c = 4; // 编译错误,不能将参数转换成Cat对象
Cat c2(4); // 正常编译通过,创建1个小猫,有4条腿
return 0;
}
上面的例子中,Animal类的构造函数没有被标记为explicit,因此可以通过传递一个int类型的参数隐式创建Animal对象。但是,在Cat类中,构造函数被标记为explicit,因此不能通过隐式传递参数来创建Cat对象。只能通过显式调用Cat的构造函数来创建它。
总的来说,使用explicit关键字可以避免程序员在类型转换时出现不必要的错误,避免潜在的bug。
extern 关键字
C++中extern关键字用于声明一个外部变量或函数。当在一个文件中定义了一个全局变量或函数时,可以通过extern关键字在其他文件中使用它们。这样就可以在不同的文件间共享变量或函数,使得程序的模块化更加灵活。
extern关键字的其他用法包括:
1. 声明一个已经在其他文件中定义的全局变量或函数。这种用法通常出现在头文件中。
2. 在一个函数或代码块中声明一个全局变量或函数,使其在这个函数或代码块的范围内有效。
例如,假设在一个文件中定义了一个全局变量:
int globalVar = 1;
然后在另一个文件中可以使用extern关键字来引用它:
extern int globalVar;
这样就可以在第二个文件中使用globalVar变量,而不需要重新定义它。
另外需要注意的是,在使用extern关键字时,变量或函数的定义应该在声明之前出现,否则编译器可能会无法识别。
typedef 关键字
C++ 中的 typedef 可以用来给一个类型起一个新的别名,以方便代码的使用。typedef 的常见用法包括:
1. 给基本类型起别名
typedef int Integer;
typedef double Real;
typedef char Char;
这样就可以用 Integer、Real 和 Char 来代替 int、double 和 char。
2. 给复杂类型起别名
typedef std::vector<int> IntVec;
typedef std::pair<int, double> Pair;
typedef std::function<int(int)> IntFunc;
这里 std::vector<int> 是一个复杂的数据类型,IntVec 就是对其的一种别名。同时也可以给 std::pair<int, double> 和 std::function<int(int)> 这样的复杂类型起别名。
3. 使用 typedef 来定义函数指针类型
typedef int (*IntFuncPtr)(int);
这里定义了一个 IntFuncPtr 的类型,它是一个指向返回值为 int、参数为 int 的函数指针类型。
4. 进一步复杂的用法
typedef std::vector<std::pair<int, double>> PairVec;
typedef std::function<std::vector<int>(int, double)> IntVecFunc;
typedef std::map<int, std::pair<int, double>> MapPair;
可以在 typedef 中定义更复杂的类型,如 std::vector<std::pair<int, double>>、std::function<std::vector<int>(int, double)>、std::map<int, std::pair<int, double>> 等。这样就可以用 PairVec、IntVecFunc、MapPair 这样的类型别名来代替这些复杂类型。
总之,typedef 可以用来给各种类型起简单的别名,使代码更加易读、易写。但要注意不要过分滥用,使代码过于冗长、难读。
static_cast 关键字
C++ 中的 `static_cast` 是一种基本的类型转换操作符,其主要作用是将一个类型转换为另一个类型。它可以用于将一种类型的值(或表达式)转换为另一种类型的值,包括基本类型、指针类型和引用类型。
使用 `static_cast` 转换时,通常需要注意以下几点:
- 转换的源类型和目标类型之间必须存在某种类型转换规则;
- 转换过程中可能会出现类型信息的损失,需要进行精度损失的检查;
- 不能用于自定义类型的转换。
下面是一些使用 `static_cast` 的示例:
int i = 10;
double d = static_cast<double>(i); // 将整型变量 i 转换为浮点型变量 d
char c = static_cast<char>(i); // 将整型变量 i 转换为字符型变量 c
int* p = &i;
double* pd = static_cast<double*>(p); // 将指向整型变量 i 的指针 p 转换为指向浮点型变量的指针 pd
const int ci = 10;
int& ri = const_cast<int&>(ci); // 将常量 ci 转换为普通的整型
class A { };
class B : public A { };
A* pa = new B;
B* pb = static_cast<B*>(pa); // 将指向 A 类对象的指针 pa 转换为指向 B 类对象的指针 pb
operator 关键字
C++ operator是指C++中的运算符,包括算术运算符、逻辑运算符、位运算符、关系运算符、赋值运算符等。每个运算符都有特定的操作数和语法。
例如,加法运算符“+”是一个二元运算符,它的操作数可以是整数、浮点数、字符串等。而自增运算符“++”是一个一元运算符,它只有一个操作数。C++中还有许多特殊的运算符,如成员访问运算符“.”、指向成员运算符“->”等。
除了默认的运算符外,C++还提供了重载运算符的功能,开发人员可以根据自己的需要对运算符进行重新定义。例如,可以重载“+”运算符,使其用于自定义类型的加法运算。
总之,C++ operator是C++中的运算符,其包含各种不同类型的运算符,以及重载运算符的功能。掌握这些运算符的用法和语法规则对于使用C++进行编程是非常重要的。
auto 关键字
在C++中,auto
关键字用于让编译器自动推导变量的类型。它可以让开发者在声明变量时省略类型,从而简化代码和提高可读性。
auto
关键字的使用方法很简单,只需要将变量声明中的类型部分替换为auto
即可。编译器会根据变量的初始化表达式推导出变量的类型。例如:
auto x = 10; // 推导为int类型
auto y = 3.14; // 推导为double类型
auto str = "Hello, world!"; // 推导为const char*类型
// lambda函数的返回类型也可以使用auto
auto sum = [](int a, int b) { return a + b; };
auto
关键字的使用有以下几点需要注意:
-
auto
关键字只能用于自动类型推导,不能用于函数参数、返回值、类成员等声明中。 -
auto
关键字在编译时会根据初始化表达式进行类型推导,因此必须确保初始化表达式可用于推导类型。 -
当初始化表达式为引用类型时,
auto
关键字会保留引用特性。例如:int x = 10; auto& ref = x; // 推导为int&类型,ref是x的引用
-
在C++14之前,
auto
关键字推导的类型不能是模板类型,只能是具体类型。从C++14开始,引入了更通用的类型推导方式:decltype(auto)
。int x = 10; decltype(auto) a = x; // 推导为int类型 decltype(auto) b = (x); // 推导为int&类型,注意圆括号的影响
使用auto
关键字可以减少代码中的类型冗余,提高代码的可读性和可维护性。然而,过度使用auto
可能会降低代码的可读性,因此在选择使用时需要考虑代码的可读性和可维护性之间的平衡。
C++ 智能指针
C++中的智能指针是一种用于管理动态分配内存的工具,它能够帮助开发者自动处理内存的分配和释放,以避免内存泄漏和悬挂指针等问题。
C++标准库提供了两种主要的智能指针:std::unique_ptr
和std::shared_ptr
。
std::unique_ptr
是一种独占的智能指针,它在其生命周期内保证只有一个指针可以指向分配的对象。当std::unique_ptr
被销毁时,它会自动释放所管理的内存。因为它只允许一个指针拥有对象的所有权,所以不能进行复制操作,只能通过移动语义转移所有权。
下面是使用std::unique_ptr
的示例代码:
#include <memory>
int main() {
std::unique_ptr<int> ptr(new int(5));
// 使用智能指针管理的对象
std::cout << *ptr << std::endl;
// 不需要手动释放内存,智能指针会自动处理
return 0;
}
std::shared_ptr
是一种共享的智能指针,它允许多个指针同时拥有对象的所有权。内部使用引用计数来跟踪对象的引用数,当引用数为零时,该对象将被自动删除。与std::unique_ptr
不同,std::shared_ptr
可以进行复制操作。
下面是使用std::shared_ptr
的示例代码:
#include <memory>
int main() {
std::shared_ptr<int> ptr1(new int(5));
// 复制智能指针,引用计数加一
std::shared_ptr<int> ptr2 = ptr1;
// 使用智能指针管理的对象
std::cout << *ptr1 << std::endl;
std::cout << *ptr2 << std::endl;
// 不需要手动释放内存,智能指针会自动处理
return 0;
}
使用智能指针可以减轻手动管理内存的负担,提高代码的安全性和可维护性。然而,需要注意的是,智能指针并不能解决所有的内存管理问题,在使用过程中仍然需要注意避免循环引用等问题。
类型转换关键字
在C++中,有几种方式可以进行类型转换,具体取决于需要的转换方式和类型之间的关系。以下是C++中常用的类型转换方式:
-
静态转换(Static Cast):
- 用于基本类型之间的转换,如整数和浮点数之间的转换。
- 用于具有继承关系的类之间的转换,但不能用于无关的类之间的转换。
- 在进行转换时,编译器只进行静态检查,不进行运行时检查。
-
重新解释转换(Reinterpret Cast):
- 用于将一个指针或引用转换为另一种类型的指针或引用。
- 可以将指针转换为整数类型,并进行逆向转换。
-
常量转换(Const Cast):
- 用于从一个常量类型转换为非常量类型,或者从一个非常量类型转换为常量类型。
- 主要用于去除 const 属性,以便修改对象。
-
动态转换(Dynamic Cast):
- 用于具有继承关系的类之间的转换。
- 在进行转换时,会进行运行时类型检查,如果转换不成功,则返回空指针或引发异常。
除了上述常用的类型转换方式,C++还支持其他一些特殊的类型转换,如模板类型转换、引用转换等。需要根据具体的场景和需求选择合适的类型转换方式,并遵守类型转换的规则和最佳实践。
需要注意的是,类型转换可能会引入一定的风险和副作用,因此在进行类型转换时应谨慎,并确保转换是安全和合理的。错误或不当的类型转换可能导致程序运行时错误和未定义的行为。
mutable 关键字
mutable
是C++中的一个关键字,用于声明类的成员变量为可变的(mutable),即使在常量成员函数内部也可以修改它们的值。
通常情况下,常量成员函数(const member function)被设计为不会修改类的状态。但有时候,存在一些特殊情况下需要在常量成员函数内部修改某些成员变量的值,这时可以将这些成员变量声明为mutable
。
下面是一个使用mutable
的示例:
class MyClass {
public:
void setCount(int count) const {
// 在常量成员函数内部修改成员变量的值
// 在 count 被声明为 mutable 之前,这样的操作是不允许的
m_count = count;
}
private:
mutable int m_count;
};
在上述示例中,m_count
被声明为mutable
,因此即使在常量成员函数setCount
内部,也可以修改m_count
的值。
需要注意的是,mutable
关键字只能用于非静态成员变量(即对象的成员变量),不能用于函数、静态成员变量或全局变量。
使用mutable
关键字时,应注意在合适的场景下使用,避免滥用。同时,需要注意在常量成员函数内部更改mutable
变量的值可能对对象的状态产生副作用,因此要确保它们的使用是安全和合理的。
成员访问权限
在C++中,private、protected和public是用于定义类中成员访问权限的三个关键字。
-
private:
- 私有成员用private关键字进行修饰,只能在类的内部访问,类的外部无法直接访问私有成员。
- 私有成员对于类的用户是不可见的,只能通过类的公有成员函数来间接访问。
-
protected:
- 在继承关系中,protected关键字与private关键字具有相似的行为,它们都限制了成员的直接访问。
- protected成员可以在派生类中访问,但无法在类的用户或非派生类中直接访问。
-
public:
- 公有成员用public关键字进行修饰,可以在类的内部和外部被访问。
- 公有成员对于类的用户是可见的,可以直接通过对象访问或者使用成员访问操作符来访问。