explicit
关键字
explicit
是 C++ 中的一个关键字,用于修饰构造函数或转换运算符,目的是防止编译器进行隐式类型转换。它主要用于防止构造函数或转换运算符在不明确的情况下被自动调用。
防止隐式类型转换
当没有 explicit
关键字时,C++ 编译器可以在某些情况下自动将一个类型转换为另一个类型,这就是所谓的隐式类型转换。比如:
class MyClass {
public:
MyClass(int val) {
// 构造函数
}
};
void func(MyClass obj) {
//...
}
int main() {
func(10); // 这里10会隐式地转换为MyClass(10)
return 0;
}
在上面的代码中,func
函数期望一个 MyClass
类型的参数,编译器会自动使用 MyClass(int)
构造函数将 10
转换为 MyClass
对象。这种隐式转换有时会导致意外的行为,特别是当有多个重载构造函数时。
为了防止这种隐式类型转换,可以使用 explicit
关键字修饰构造函数:
class MyClass {
public:
explicit MyClass(int val) {
// 构造函数
}
};
在这个例子中,MyClass(int)
被标记为 explicit
,所以编译器不会允许隐式地将 int
转换为 MyClass
类型。如果你需要手动进行转换,可以显式调用构造函数:
func(MyClass(10)); // 显式调用构造函数
什么时候使用 explicit
- 避免意外的隐式转换:一个单参数的构造函数,尤其是当它可以与其他类型的构造函数重载时,应该使用
explicit
以防止自动类型转换带来意外的行为。 - 控制类型转换的时机:希望类型转换只在明确的情况下进行,而不是编译器自动推断时,就应该使用
explicit
。
静态成员
在 C++ 中,
static
关键字用于定义静态成员变量和静态成员函数。static
成员具有一些独特的属性
静态成员变量
定义:
- 静态成员变量属于类,而不属于类的任何特定对象。这意味着静态成员变量对于所有对象是共享的,而不是每个对象都有自己的副本。
- 静态成员变量必须在类外部进行定义,否则编译器会报错。
特性
- 共享性:所有类的对象都共享静态成员变量。无论创建多少个对象,它们都访问同一个静态成员变量。
- 生命周期:静态成员变量的生命周期与程序的生命周期相同,它在整个程序运行期间存在。
- 内存分配:静态成员变量只会在程序启动时分配一次内存,不同对象之间共享这一块内存。
静态成员函数
定义
- 静态成员函数是属于类本身的函数,而不是属于类的对象。静态成员函数只能访问类的静态成员变量和静态成员函数,因为它们与具体的对象无关。
- 静态成员函数不能访问非静态成员变量和非静态成员函数,因为静态函数没有
this
指针。
特性
- 不需要对象:静态成员函数可以直接通过类名调用,而不需要实例化对象。
- 访问限制:静态成员函数只能访问静态成员变量或其他静态成员函数,无法访问普通的非静态成员。
静态数据成员的初始化
- 静态数据成员在类内声明时可以指定默认值,但它必须在类外进行定义和初始化。
- 静态成员变量的定义通常在类外进行,而不能仅仅在类内部声明。
静态成员变量的作用
- 共享数据:静态成员变量对于所有的类对象是共享的。这使得它非常适合存储那些与类的所有实例共享的数据,如类的实例计数、全局配置等。
- 对象间共享状态:静态成员变量可以用于在多个对象之间共享状态。例如,创建一个计数器来记录类的对象数。
总结
- 静态成员变量是类的共享变量,在所有对象间共享,可以通过类名直接访问。
- 静态成员函数只能访问静态成员,不能访问非静态成员。
- 静态成员变量必须在类外定义。
一个例子
创建一个计数器来记录类的对象数
class MyClass
{
public:
MyClass()
{
_count++;// 每次创建对象,_count++
}
static int GetCount()
{
return _count;
}
private:
static int _count;// 静态成员变量
};
int MyClass::_count = 0;// 静态成员变量初始化
int main() {
MyClass m1, m2, m3;
cout << MyClass::GetCount() << endl;
return 0;
}