美文网首页
=default、=delete、override

=default、=delete、override

作者: hehehehe | 来源:发表于2024-08-29 15:57 被阅读0次

    在 C++11 及其后续版本中,= default 用于显式地指定编译器生成默认的构造函数、析构函数或拷贝/移动操作符。它允许你在类定义中明确地表示你希望使用编译器生成的默认实现,而不是自己手动实现这些函数。

    语法

    class MyClass {
    public:
        MyClass() = default;             // 默认构造函数
        ~MyClass() = default;            // 默认析构函数
        MyClass(const MyClass&) = default; // 拷贝构造函数
        MyClass& operator=(const MyClass&) = default; // 拷贝赋值操作符
        MyClass(MyClass&&) = default;    // 移动构造函数
        MyClass& operator=(MyClass&&) = default; // 移动赋值操作符
    };
    

    使用场景

    1. 显式要求编译器生成默认函数:当你希望编译器生成默认的函数实现时,可以使用 = default。这在某些情况下是必须的,例如当你有其他的构造函数或析构函数时,编译器不会自动生成默认的构造函数或其他特殊成员函数。

      class MyClass {
      public:
          MyClass(int value) : value(value) {} // 自定义构造函数
      
          MyClass() = default; // 显式要求编译器生成默认构造函数
      
      private:
          int value;
      };
      
    2. 性能优化:有时编译器生成的默认实现比手动实现更高效,因为编译器可以直接生成内联代码。

    3. 确保特殊成员函数是 trivialconstexpr:使用 = default 可以保证某些情况下生成的特殊成员函数是 trivialconstexpr 的。

    示例

    以下是一个简单的示例,展示了如何使用 = default

    #include <iostream>
    
    class MyClass {
    public:
        MyClass() = default; // 默认构造函数
        ~MyClass() = default; // 默认析构函数
    
        MyClass(const MyClass&) = default; // 拷贝构造函数
        MyClass& operator=(const MyClass&) = default; // 拷贝赋值操作符
    
        MyClass(MyClass&&) = default; // 移动构造函数
        MyClass& operator=(MyClass&&) = default; // 移动赋值操作符
    
        void display() const {
            std::cout << "MyClass instance" << std::endl;
        }
    };
    
    int main() {
        MyClass obj1; // 调用默认构造函数
        MyClass obj2 = obj1; // 调用拷贝构造函数
        MyClass obj3 = std::move(obj1); // 调用移动构造函数
    
        obj2 = obj3; // 调用拷贝赋值操作符
        obj3 = std::move(obj2); // 调用移动赋值操作符
    
        obj1.display();
        obj2.display();
        obj3.display();
    
        return 0;
    }
    

    在这个示例中,MyClass 使用 = default 显式要求编译器生成默认的构造函数、析构函数、拷贝构造函数、拷贝赋值操作符、移动构造函数和移动赋值操作符。

    注意事项

    • 如果你定义了一个类的某些特殊成员函数(如构造函数、析构函数、拷贝/移动操作符),编译器将不会自动生成其他的默认特殊成员函数。此时你可以使用 = default 显式地要求编译器生成它们。
    • = default 只能用于特殊成员函数(构造函数、析构函数、拷贝/移动构造函数和拷贝/移动赋值操作符)。
    • 如果某个默认的特殊成员函数被标记为 = delete,则不能使用 = default

    通过使用 = default,你可以更清晰地表达你的意图,并且在某些情况下还能获得更好的性能和代码优化。

    = delete

    = delete 用于显式删除某个函数,表示该函数不可用。通常用于删除特殊成员函数,如拷贝构造函数、拷贝赋值操作符等,以防止对象被不正确地复制或赋值。

    class MyClass {
    public:
        MyClass() = default; // 默认构造函数
        MyClass(const MyClass&) = delete; // 删除拷贝构造函数
        MyClass& operator=(const MyClass&) = delete; // 删除拷贝赋值操作符
    };
    
    int main() {
        MyClass obj1;
        // MyClass obj2 = obj1; // 错误:拷贝构造函数被删除
        // MyClass obj3;
        // obj3 = obj1; // 错误:拷贝赋值操作符被删除
        return 0;
    }
    

    constexpr

    constexpr 用于指定一个函数或变量可以在编译时求值。对于构造函数,constexpr 表示该构造函数可以用于生成常量表达式。

    class MyClass {
    public:
        constexpr MyClass(int value) : value(value) {}
        constexpr int getValue() const { return value; }
    private:
        int value;
    };
    
    int main() {
        constexpr MyClass obj(42);
        static_assert(obj.getValue() == 42, "Value should be 42");
        return 0;
    }
    

    noexcept

    noexcept 用于指定一个函数不会抛出异常。这在优化和异常安全性方面很有用。

    class MyClass {
    public:
        MyClass() noexcept = default;
        void doSomething() noexcept {
            // 不会抛出异常的代码
        }
    };
    
    int main() {
        MyClass obj;
        obj.doSomething();
        return 0;
    }
    

    override

    override 用于显式指定一个虚函数覆盖了基类中的虚函数。这样可以帮助编译器检查函数签名是否匹配,防止因为签名不匹配而意外地创建了一个新的虚函数。

    class Base {
    public:
        virtual void doSomething() {}
    };
    
    class Derived : public Base {
    public:
        void doSomething() override {
            // 覆盖基类中的虚函数
        }
    };
    

    final

    final 用于指定一个类不能被继承,或者一个虚函数不能被进一步覆盖。

    class Base {
    public:
        virtual void doSomething() final {
            // 这个虚函数不能被覆盖
        }
    };
    
    class Derived final : public Base {
        // 这个类不能被继承
    };
    

    explicit

    explicit 用于防止构造函数或转换运算符在不需要时隐式转换。这有助于避免意外的类型转换。

    class MyClass {
    public:
        explicit MyClass(int value) : value(value) {}
    private:
        int value;
    };
    
    int main() {
        // MyClass obj = 42; // 错误:构造函数是 explicit 的
        MyClass obj(42); // 正确
        return 0;
    }
    

    总结

    这些关键字和特性提供了更细粒度的控制和更强的表达能力,使得代码更加清晰、健壮和高效。通过合理使用这些关键字和特性,你可以编写出更易于维护和理解的代码。

    相关文章

      网友评论

          本文标题:=default、=delete、override

          本文链接:https://www.haomeiwen.com/subject/ztpxljtx.html