<C++> C++11新的类功能

C++11新的类功能

1.默认成员函数

原来C++类中,有6个默认成员函数:

  1. 构造函数
  2. 析构函数
  3. 拷贝构造函数
  4. 拷贝赋值重载
  5. 取地址重载
  6. const取地址重载

最后重要的是前4个,后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。

C++11 新增了两个:移动构造函数和移动赋值运算符重载

针对移动构造函数移动赋值运算符重载有一些需要注意的点如下:

  • 如果你没有自己实现移动构造函数,且没有实现析构函数拷贝构造拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝自定义类型成员,则需要看这个成员是否实现移动构造, 如果实现了就调用移动构造没有实现就调用拷贝构造
  • 移动赋值重载同上规则相同
  • 如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

以下代码在vs2013中不能体现,在vs2019下才能演示体现上面的特性。

namespace phw {
    
    
    class string {
    
    
    public:
        typedef char *iterator;
        iterator begin() {
    
    
            return _str;
        }

        iterator end() {
    
    
            return _str + _size;
        }

        string(const char *str = "")
            : _size(strlen(str)), _capacity(_size) {
    
    
            //cout << "string(char* str)" << endl;

            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }

        // s1.swap(s2)
        void swap(string &s) {
    
    
            ::swap(_str, s._str);
            ::swap(_size, s._size);
            ::swap(_capacity, s._capacity);
        }

        // 拷贝构造
        string(const string &s)
            : _str(nullptr) {
    
    
            cout << "string(const string& s) -- 深拷贝" << endl;

            string tmp(s._str);
            swap(tmp);
        }

        // 移动构造
        string(string &&s)
            : _str(nullptr) {
    
    
            cout << "string(string&& s) -- 移动拷贝" << endl;
            swap(s);
        }

        // 赋值重载
        string &operator=(const string &s) {
    
    
            cout << "string& operator=(string s) -- 深拷贝" << endl;
            string tmp(s);
            swap(tmp);

            return *this;
        }

        // s1 = 将亡值
        string &operator=(string &&s) {
    
    
            cout << "string& operator=(string&& s) -- 移动赋值" << endl;
            swap(s);

            return *this;
        }

        ~string() {
    
    
            //cout << "~string()" << endl;

            delete[] _str;
            _str = nullptr;
        }

        char &operator[](size_t pos) {
    
    
            return _str[pos];
        }

        void reserve(size_t n) {
    
    
            if (n > _capacity) {
    
    
                char *tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;

                _capacity = n;
            }
        }

        void push_back(char ch) {
    
    
            if (_size >= _capacity) {
    
    
                size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
                reserve(newcapacity);
            }

            _str[_size] = ch;
            ++_size;
            _str[_size] = '\0';
        }

        //string operator+=(char ch)
        string &operator+=(char ch) {
    
    
            push_back(ch);
            return *this;
        }

        string operator+(char ch) {
    
    
            string tmp(*this);
            tmp += ch;
            return tmp;
        }

        const char *c_str() const {
    
    
            return _str;
        }

    private:
        char *_str;
        size_t _size;
        size_t _capacity;// 不包含最后做标识的\0
    };

    //const bit::string& to_string(int value)
    phw::string to_string(int value) {
    
    
        bool flag = true;
        if (value < 0) {
    
    
            flag = false;
            value = 0 - value;
        }

        phw::string str;
        while (value > 0) {
    
    
            int x = value % 10;
            value /= 10;

            str += ('0' + x);
        }

        if (flag == false) {
    
    
            str += '-';
        }

        std::reverse(str.begin(), str.end());
        return str;
    }
}// namespace phw

// 以下代码在vs2013中不能体现,在vs2019下才能演示体现上面的特性。
class Person {
    
    
public:
    Person(const char *name = "", int age = 0)
        : _name(name), _age(age) {
    
    }

    Person(const Person &p)
        : _name(p._name), _age(p._age) {
    
    }

    Person &operator=(const Person &p) {
    
    
        if (this != &p) {
    
    
            _name = p._name;
            _age = p._age;
        }
        return *this;
    }

    // 强制生成移动构造和移动赋值
    Person(Person &&p) = default;
    Person &operator=(Person &&p) = default;

    ~Person() {
    
    
        cout << "~Person()" << endl;
    }

private:
    phw::string _name;// 自定义类型
    int _age = 1;     // 内置类型
};

int main() {
    
    
    Person s1("张三", 18);
    Person s2 = s1;
    Person s3 = std::move(s1);
    cout << endl;


    return 0;
}

在这里插入图片描述

2.关键字delete

delete关键字用于显式地禁用某些特殊成员函数或运算符,以阻止它们在特定的上下文中被调用或使用。

使用delete关键字,可以在类的声明中删除以下函数:

  1. 删除默认构造函数:

    MyClass() = delete;
    

    这将禁用默认构造函数,阻止对象的无参创建。

  2. 删除复制构造函数和复制赋值运算符:

    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;
    

    这将阻止对象的复制,即禁止使用拷贝构造函数和复制赋值运算符进行对象的复制。

  3. 删除移动构造函数和移动赋值运算符:

    MyClass(MyClass&&) = delete;
    MyClass& operator=(MyClass&&) = delete;
    

    这将阻止对象的移动语义,即禁止使用移动构造函数和移动赋值运算符进行对象的移动操作。

  4. 删除析构函数:

    ~MyClass() = delete;
    

    这将阻止对象的销毁,即禁止调用析构函数进行对象的内存释放。

通过使用delete关键字,可以在编译期间捕捉到一些潜在的错误或不正确的使用。例如,如果尝试复制或移动被删除的函数,编译器将会产生错误。

示例:

class MySingleton {
    
    
private:
    MySingleton() = delete;  // 默认构造函数被删除
    MySingleton(const MySingleton&) = delete;  // 复制构造函数被删除
    MySingleton& operator=(const MySingleton&) = delete;  // 复制赋值运算符被删除

public:
    static MySingleton& getInstance() {
    
    
        static MySingleton instance;
        return instance;
    }

    void doSomething() {
    
    
        // 执行操作
    }
};

int main() {
    
    
    MySingleton& singleton = MySingleton::getInstance();
    singleton.doSomething();

    // 错误示例,尝试创建被删除的默认构造函数的对象
    // MySingleton singleton2;  // 编译错误

    return 0;
}

在上面的示例中,通过删除默认构造函数、复制构造函数和复制赋值运算符,实现了一个单例模式的类。这样,阻止了通过复制或拷贝方式创建多个实例。任何尝试复制的操作都会在编译时被捕获并产生错误。

总结来说,C++11的delete关键字为开发者提供了更大的灵活性,可以显式地删除某些函数,以避免在特定情况下的误用和错误。这是C++中一个强大的特性,有助于更好地控制类的行为和语义。

3.final与override

在C++11标准中,关键字finaloverride用于类的继承和虚函数的重写。它们提供了一种显式的方法来控制和标记继承关系和函数重写。

3.1 final

final关键字用于修饰类、虚函数或成员函数,表示它们不能被继承或重写。具体来说:

  • 当应用于类时,final关键字表示该类不能被其他类继承。
  • 当应用于虚函数时,final关键字表示该虚函数不能被派生类重写。
  • 当应用于成员函数时,final关键字表示该成员函数不能在派生类中被重写。

以下是使用final关键字的示例:

class Base final {
    
    
    // ...
};

class Derived : public Base {
    
      // 错误,无法继承被标记为final的类
    // ...
};

class Base {
    
    
public:
    virtual void foo() const final;
};

class Derived : public Base {
    
    
public:
    void foo() const override;  // 错误,无法重写被标记为final的虚函数
};

class Base {
    
    
public:
    virtual void foo() const;
};

class Derived : public Base {
    
    
public:
    void foo() const final;  // 错误,无法在派生类中重写被标记为final的成员函数
};

3.2 override

override关键字用于显式地标记派生类中的成员函数,以表明它们是基类中虚函数的重写版本。使用override关键字可以增强代码的可读性和可维护性,并帮助编译器检测错误。如果派生类中的函数声明使用了override关键字,但却没有重写基类中的虚函数,则会导致编译错误。

以下是使用override关键字的示例:

class Base {
    
    
public:
    virtual void foo() const{
    
    }
};

class Derived : public Base {
    
    
public:
    void foo() const override{
    
    }  // 表示该函数是基类虚函数的重写版本
};

class Base {
    
    
public:
    virtual void foo() const{
    
    }
};

class Derived : public Base {
    
    
public:
    void foo() const{
    
    }  // 错误,没有使用override关键字重写基类的虚函数,编译器不会报错
};

override关键字的示例:

class Base {
    
    
public:
    virtual void foo() const{
    
    }
};

class Derived : public Base {
    
    
public:
    void foo() const override{
    
    }  // 表示该函数是基类虚函数的重写版本
};

class Base {
    
    
public:
    virtual void foo() const{
    
    }
};

class Derived : public Base {
    
    
public:
    void foo() const{
    
    }  // 错误,没有使用override关键字重写基类的虚函数,编译器不会报错
};

注意,在C++11之前,虚函数的重写是隐式的,不需要使用override关键字。但是,使用override关键字可以提供更明确的语义和更好的编译时错误检测。

猜你喜欢

转载自blog.csdn.net/ikun66666/article/details/131324978
今日推荐