1. override
override 是一个关键字,用于显式地标记派生类中重写(覆盖)基类虚函数的意图。
override
并不会影响程序的执行结果,仅仅是作用于编译阶段,用于检查子类是否真的重写父类函数
- 作用:
- 帮助发现错误:使用override关键字可以帮助开发者在编译时检测到派生类中虚函数重写的错误。如果派生类中的函数签名与基类的虚函数不匹配,编译器会报错,从而避免潜在的bug。
- 代码维护:在大型项目中,当基类的虚函数发生变化时,使用override关键字可以确保派生类中对应的函数得到正确的更新。如果派生类中的函数名与基类的虚函数不匹配,则编译器会产生错误,提醒开发者更新派生类的函数实现。
- 代码展示
#include <iostream>// 基类 Animal
class Animal {
public:virtual void makeSound() {std::cout << "Animal makes a sound.\n";}
};// 派生类 Dog
class Dog : public Animal {
public:void makeSound() override {std::cout << "Dog barks.\n";}
};// 派生类 Cat
class Cat : public Animal {
public:void makeSound() override {std::cout << "Cat meows.\n";}
};int main() {// 创建 Animal 指针,并指向 Dog 对象Animal* animal = new Dog();animal->makeSound(); // 输出:Dog barks.// 将 Animal 指针指向 Cat 对象animal = new Cat();animal->makeSound(); // 输出:Cat meows.// 定义 Animal 指针数组,并存储 Dog 和 Cat 对象Animal* animals[] = {new Dog(), new Cat()};// 遍历指针数组,调用 makeSound() 函数for (int i = 0; i < 2; i++) {animals[i]->makeSound();}// 释放内存for (int i = 0; i < 2; i++) {delete animals[i];}return 0;
}
2. final
在C++中,final是一个关键字,用于限制类、成员函数或虚函数的进一步派生或重写。
- 作用:
- 防止类被继承:通过在类声明中标记为final,可以显式地指示该类不可被继承。这在设计中可以用于限制类的层次结构或确保某个类的特定实现不被修改。
- 防止虚函数被重写:通过在虚函数声明中标记为final,可以阻止派生类对该虚函数进行重写。这在某些情况下可以用于确保基类的某个虚函数的实现不被修改或被误重写。
- 代码展示:
#include <iostream>using namespace std;class father{
public:virtual void done() final {}};class son final : public father{
public://void done() {} 报错 Declaration of 'done' overrides a 'final' function};// class grandson: public son{ }; 报错 Base 'son' is marked 'final' 'son' declared hereint main() {father * f = new son();f->done();return 0;
}
3. delete
在C++中,delete是一个类内关键字,用于显式 禁用 | 删除 特殊成员函数或运算符。它的作用是阻止编译器自动生成该函数或运算符。
- 作用:
- 防止函数的使用:通过将某个函数声明为 delete,可以防止该函数被意外调用,从而避免潜在的错误或不正确的使用。
- 禁用默认函数:通过将特殊成员函数(如拷贝构造函数和拷贝赋值运算符)声明为 delete,可以禁用类的默认实现,强制用户提供自定义的实现或禁用特定的行为。
- 禁止拷贝和赋值:通过将拷贝构造函数和拷贝赋值运算符声明为 delete,可以禁止对象的拷贝和赋值操作,以确保对象的唯一性或禁止不必要的资源管理。
- 使用场景:
- 禁止拷贝和赋值:当某个类的对象不应该被拷贝或赋值时,可以将拷贝构造函数和拷贝赋值运算符声明为 delete。这在单例模式或具有独占资源的类中很常见。
class NonCopyable {
public:NonCopyable() = default;~NonCopyable() = default;// 禁用拷贝构造函数NonCopyable(const NonCopyable&) = delete;// 禁用拷贝赋值运算符NonCopyable& operator=(const NonCopyable&) = delete;
};int main() {NonCopyable obj1;NonCopyable obj2(obj1); // 错误!无法调用被删除的拷贝构造函数NonCopyable obj3;obj3 = obj1; // 错误!无法调用被删除的拷贝赋值运算符return 0;
}
- 禁用默认函数:当类的默认实现不符合需求时,可以将特殊成员函数(如拷贝构造函数和拷贝赋值运算符)声明为 delete,以禁用类的默认实现。这在禁止对象拷贝、禁止对象拷贝到容器等场景中很有用。
class NoDefaultConstructor {
public:// 禁用默认构造函数NoDefaultConstructor() = delete;// 自定义构造函数NoDefaultConstructor(int value) {// 构造函数实现}
};int main() {NoDefaultConstructor obj1; // 错误!无法调用被删除的默认构造函数NoDefaultConstructor obj2(42); // 正确,调用自定义构造函数return 0;
}
NoDefaultConstructor 类禁用了默认构造函数,通过将其声明为 delete。这意味着无法创建没有参数的对象,但可以通过自定义构造函数创建对象。
- 特定条件下的函数禁用:当某个函数在特定情况下不应该被调用时,可以将该函数声明为 delete。例如,当类的某个函数在特定的模板参数下无效时,可以将其声明为 delete。
#include <iostream>template <typename T>
class ConditionalFunction {
public:// 删除函数,当 T 是指针类型时禁用void Process(T value) {static_assert(!std::is_pointer_v<T>, "This function is disabled for pointer types.");// 函数实现}
};int main() {ConditionalFunction<int> obj1;obj1.Process(42); // 正确,T 不是指针类型ConditionalFunction<int*> obj2;
// obj2.Process(nullptr); // 错误!无法调用被删除的函数return 0;
}
or :
#include <iostream>template <typename T>
class ConditionalFunction {
public:// 默认实现void Process(T value) {// 函数实现}
};// 针对指针类型的部分模板特化
template <typename T>
class ConditionalFunction<T*> {
public:// 禁用函数void Process(T* value) = delete;
};int main() {ConditionalFunction<int> obj1;obj1.Process(42); // 正确,T 不是指针类型ConditionalFunction<int*> obj2;// obj2.Process(nullptr); // 错误!无法调用被删除的函数return 0;
}
4. default
在C++中,default是一个关键字,用于指定默认的特殊成员函数的行为。它可以应用于以下特殊成员函数:默认构造函数、析构函数、拷贝构造函数 和 拷贝赋值运算符。
default的作用是告诉编译器使用默认的实现来生成相应的特殊成员函数。默认实现遵循特定规则,并且会执行合适的行为,比如调用基类或成员变量的对应函数。
- 使用场景:
显式请求编译器生成默认函数:当用户自定义类中没有显式定义上述特殊成员函数时,编译器会自动生成默认版本的函数。但是,如果显式使用default关键字声明这些函数,可以明确表示希望使用编译器生成的默认实现。这在需要默认行为的情况下非常有用,可以减少代码量。
class MyClass {
public:// 默认构造函数的默认实现MyClass() = default;// 析构函数的默认实现~MyClass() = default;// 拷贝构造函数的默认实现MyClass(const MyClass&) = default;// 拷贝赋值运算符的默认实现MyClass& operator=(const MyClass&) = default;
};
5. explicit
adj. 明确的;坦率的;
n. (手稿、早期印刷品或礼拜仪式上唱诗的)结束语
在 C++ 中,explicit 关键字用于修饰单参数构造函数,用于禁止隐式类型转换。它的作用是防止编译器执行隐式的构造函数调用,只允许显式地调用构造函数。
- 使用 explicit 关键字的场景包括:
防止隐式类型转换:当类的构造函数只有一个参数时,如果没有使用 explicit 关键字修饰,那么编译器将允许隐式地将该参数类型转换为类的对象。但是,使用 explicit 关键字修饰后,只能使用显式的方式调用构造函数,防止了隐式类型转换。
#include <iostream>class Distance {
private:double meters;
public:explicit Distance(double m) : meters(m) {}double getMeters() const { return meters; }
};void printDistance(const Distance& d) {std::cout << d.getMeters() << " meters" << std::endl;
}int main() {//Distance dist = 10.5; // 错误!禁止隐式类型转换Distance dist(10.5);//printDistance(20.3); // 错误!禁止隐式类型转换printDistance(Distance(20.3));return 0;
}