<C++> C++11 nueva función de clase

Características de la nueva clase de C++11

1. Funciones miembro predeterminadas

En la clase C++ original, hay 6 funciones miembro predeterminadas:

  1. Constructor
  2. incinerador de basuras
  3. copiar constructor
  4. sobrecarga de asignación de copias
  5. tomar sobrecarga de direcciones
  6. sobrecarga de direcciones constantes

Por último pero no menos importante están los 4 primeros, los dos últimos sirven de poco. La función miembro predeterminada es que si no escribimos, el compilador generará una predeterminada.

C ++ 11 agrega dos nuevos: mover constructor y mover sobrecarga del operador de asignación .

Hay algunos puntos a tener en cuenta para la sobrecarga del constructor de movimiento y del operador de asignación de movimiento de la siguiente manera:

  • Si no implementa el constructor de movimiento usted mismo , y no implementa ninguno de los destructores , copie la construcción y copie las sobrecargas de asignación . entonces el compilador generará automáticamente una construcción de movimiento predeterminada . El constructor de movimiento generado de forma predeterminada realizará una copia de miembro por miembro byte por byte para los miembros de tipo integrados. Para los miembros de tipo personalizado , debe comprobar si el miembro implementa la construcción de movimiento . Si se realiza , llame a la construcción de movimiento , y si no , llame a la construcción de copias .
  • La sobrecarga de asignación de movimiento tiene las mismas reglas que la anterior
  • Si proporciona construcción de movimiento o asignación de movimiento, el compilador no proporcionará automáticamente construcción de copia ni asignación de copia.

El siguiente código no se puede reflejar en vs2013 y las características anteriores solo se pueden demostrar en 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;
}

inserte la descripción de la imagen aquí

2. Eliminar palabra clave

deleteLas palabras clave se usan para deshabilitar explícitamente algunas funciones u operadores de miembros especiales para evitar que se llamen o usen en un contexto específico.

Usando deletela palabra clave, las siguientes funciones se pueden eliminar en la declaración de una clase:

  1. Eliminar el constructor predeterminado:

    MyClass() = delete;
    

    Esto deshabilita el constructor predeterminado, evitando la creación de objetos sin argumentos.

  2. Elimine el constructor de copia y el operador de asignación de copia:

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

    Esto evitará la copia del objeto, es decir, está prohibida la copia del objeto utilizando el constructor de copia y el operador de asignación de copia.

  3. Elimina el constructor de movimiento y el operador de asignación de movimiento:

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

    Esto evitará la semántica de movimiento del objeto, es decir, prohibirá el uso de constructores de movimiento y operadores de asignación de movimiento para operaciones de movimiento de objetos.

  4. Eliminar el destructor:

    ~MyClass() = delete;
    

    Esto impide la destrucción del objeto, es decir, prohíbe llamar al destructor para liberar la memoria del objeto.

Al usar deletela palabra clave, se pueden detectar algunos errores potenciales o un uso incorrecto durante la compilación. Por ejemplo, el compilador generará un error si intenta copiar o mover una función eliminada.

Ejemplo:

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;
}

En el ejemplo anterior, se implementa una clase singleton eliminando el constructor predeterminado, el constructor de copia y el operador de asignación de copia. Esto evita que se creen múltiples instancias por duplicación o copia. Cualquier intento de copia se detectará en tiempo de compilación y generará un error.

En resumen, las palabras clave de C++11 deletebrindan a los desarrolladores una mayor flexibilidad para eliminar explícitamente ciertas funciones para evitar el mal uso y los errores en situaciones específicas. Esta es una característica poderosa en C++ que facilita un control más preciso sobre el comportamiento y la semántica de las clases.

3. final y anulación

En el estándar C++11, las palabras clave finaly overridese utilizan para la herencia de clases y la reescritura de funciones virtuales. Proporcionan una forma explícita de controlar y marcar las relaciones de herencia y las anulaciones de funciones.

3.1 finales

finalLas palabras clave se utilizan para decorar clases, funciones virtuales o funciones miembro, lo que indica que no se pueden heredar ni anular. Específicamente:

  • Cuando se aplica a una clase, finalla palabra clave indica que la clase no puede ser heredada por otras clases.
  • Cuando se aplica a una función virtual, finalla palabra clave indica que las clases derivadas no pueden anular la función virtual.
  • Cuando se aplica a una función miembro, finalla palabra clave indica que la función miembro no se puede invalidar en clases derivadas.

Los siguientes son finalejemplos del uso de palabras clave:

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 anular

overrideLa palabra clave se usa para marcar explícitamente funciones miembro en clases derivadas para indicar que son versiones anuladas de funciones virtuales en la clase base. El uso overridede palabras clave puede mejorar la legibilidad y el mantenimiento de su código y ayudar al compilador a detectar errores. Si una declaración de función en una clase derivada usa overridela palabra clave, pero no anula la función virtual en la clase base, provocará un error de compilación.

Los siguientes son overrideejemplos del uso de palabras clave:

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关键字重写基类的虚函数,编译器不会报错
};

Ejemplo con overridepalabras clave:

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关键字重写基类的虚函数,编译器不会报错
};

Tenga en cuenta que antes de C++ 11, la anulación de funciones virtuales estaba implícita y no requería el uso de overridepalabras clave. Sin embargo, el uso overridede palabras clave puede proporcionar una semántica más explícita y una mejor detección de errores en tiempo de compilación.

Supongo que te gusta

Origin blog.csdn.net/ikun66666/article/details/131324978
Recomendado
Clasificación