• c++ 常见类内的关键字


    1. override

    override 是一个关键字,用于显式地标记派生类中重写(覆盖)基类虚函数的意图。
    override 并不会影响程序的执行结果,仅仅是作用于编译阶段,用于检查子类是否真的重写父类函数

    • 作用
    1. 帮助发现错误:使用override关键字可以帮助开发者在编译时检测到派生类中虚函数重写的错误。如果派生类中的函数签名与基类的虚函数不匹配,编译器会报错,从而避免潜在的bug。
    2. 代码维护:在大型项目中,当基类的虚函数发生变化时,使用override关键字可以确保派生类中对应的函数得到正确的更新。如果派生类中的函数名与基类的虚函数不匹配,则编译器会产生错误,提醒开发者更新派生类的函数实现。
    • 代码展示
    #include 
    
    // 基类 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    2. final

    在C++中,final是一个关键字,用于限制类、成员函数或虚函数的进一步派生或重写。

    • 作用:
    1. 防止类被继承:通过在类声明中标记为final,可以显式地指示该类不可被继承。这在设计中可以用于限制类的层次结构或确保某个类的特定实现不被修改。
    2. 防止虚函数被重写:通过在虚函数声明中标记为final,可以阻止派生类对该虚函数进行重写。这在某些情况下可以用于确保基类的某个虚函数的实现不被修改或被误重写。
    • 代码展示:
    #include 
    
    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 here
    
    
    int main() {
    
        father * f = new son();
        f->done();
    
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    3. delete

    在C++中,delete是一个类内关键字,用于显式 禁用 | 删除 特殊成员函数或运算符。它的作用是阻止编译器自动生成该函数或运算符。

    • 作用
    1. 防止函数的使用:通过将某个函数声明为 delete,可以防止该函数被意外调用,从而避免潜在的错误或不正确的使用。
    2. 禁用默认函数:通过将特殊成员函数(如拷贝构造函数和拷贝赋值运算符)声明为 delete,可以禁用类的默认实现,强制用户提供自定义的实现或禁用特定的行为。
    3. 禁止拷贝和赋值:通过将拷贝构造函数和拷贝赋值运算符声明为 delete,可以禁止对象的拷贝和赋值操作,以确保对象的唯一性或禁止不必要的资源管理。
    • 使用场景:
    1. 禁止拷贝和赋值:当某个类的对象不应该被拷贝或赋值时,可以将拷贝构造函数拷贝赋值运算符声明为 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    1. 禁用默认函数:当类的默认实现不符合需求时,可以将特殊成员函数(如拷贝构造函数和拷贝赋值运算符)声明为 delete,以禁用类的默认实现。这在禁止对象拷贝、禁止对象拷贝到容器等场景中很有用。
    class NoDefaultConstructor {
    public:
        // 禁用默认构造函数
        NoDefaultConstructor() = delete;
    
        // 自定义构造函数
        NoDefaultConstructor(int value) {
            // 构造函数实现
        }
    };
    
    int main() {
        NoDefaultConstructor obj1; // 错误!无法调用被删除的默认构造函数
        NoDefaultConstructor obj2(42); // 正确,调用自定义构造函数
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    NoDefaultConstructor 类禁用了默认构造函数,通过将其声明为 delete。这意味着无法创建没有参数的对象,但可以通过自定义构造函数创建对象。

    1. 特定条件下的函数禁用:当某个函数在特定情况下不应该被调用时,可以将该函数声明为 delete。例如,当类的某个函数在特定的模板参数下无效时,可以将其声明为 delete。
    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    or :

    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    4. default

    在C++中,default是一个关键字,用于指定默认的特殊成员函数的行为。它可以应用于以下特殊成员函数:默认构造函数析构函数拷贝构造函数拷贝赋值运算符

    default的作用是告诉编译器使用默认的实现来生成相应的特殊成员函数。默认实现遵循特定规则,并且会执行合适的行为,比如调用基类或成员变量的对应函数。

    • 使用场景:

    显式请求编译器生成默认函数:当用户自定义类中没有显式定义上述特殊成员函数时,编译器会自动生成默认版本的函数。但是,如果显式使用default关键字声明这些函数,可以明确表示希望使用编译器生成的默认实现。这在需要默认行为的情况下非常有用,可以减少代码量。

    class MyClass {
    public:
        // 默认构造函数的默认实现
        MyClass() = default;
    
        // 析构函数的默认实现
        ~MyClass() = default;
    
        // 拷贝构造函数的默认实现
        MyClass(const MyClass&) = default;
    
        // 拷贝赋值运算符的默认实现
        MyClass& operator=(const MyClass&) = default;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    5. explicit

    adj. 明确的;坦率的;
    n. (手稿、早期印刷品或礼拜仪式上唱诗的)结束语
    
    • 1
    • 2

    在 C++ 中,explicit 关键字用于修饰单参数构造函数,用于禁止隐式类型转换。它的作用是防止编译器执行隐式的构造函数调用,只允许显式地调用构造函数。

    • 使用 explicit 关键字的场景包括

    防止隐式类型转换:当类的构造函数只有一个参数时,如果没有使用 explicit 关键字修饰,那么编译器将允许隐式地将该参数类型转换为类的对象。但是,使用 explicit 关键字修饰后,只能使用显式的方式调用构造函数,防止了隐式类型转换。

    #include 
    
    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    6.

  • 相关阅读:
    C语言中,字节对齐是一种重要的内存管理概念
    DRF-项目-(1):构建纯净版的drf项目,不再使用django的后台管理,django的认证,django的session等功能,作为一个纯接口项目
    uniappQQ登录是如何实现的,请说明其流程
    Vue3.2组件如何封装,以弹窗组件的封装为例
    2022前端面试—CSS篇
    GitHub/R3D3项目环境配置踩坑记录
    Excel-lookup函数核对两个表格的数据匹配
    基于servlet3.0搭建spring mvc应用 无web.xml 无spring boot
    建模杂谈系列170 APIFunc继续实践-数据处理体系
    从哪里下载 Oracle database 11g 软件
  • 原文地址:https://blog.csdn.net/weixin_40378209/article/details/133920773