<C++> C++11 new class function

C++11 New Class Features

1. Default member functions

In the original C++ class, there are 6 default member functions:

  1. Constructor
  2. destructor
  3. copy constructor
  4. copy assignment overloading
  5. take address overload
  6. const address overloading

Last but not least are the first 4, the latter two are of little use. The default member function is that if we don't write the compiler will generate a default one.

C++11 adds two new ones: move constructor and move assignment operator overloading .

There are some points to note for move constructor and move assignment operator overloading as follows:

  • If you do not implement the move constructor yourself , and do not implement any of the destructor , copy construction , and copy assignment overloads . then the compiler will automatically generate a default move construct . The move constructor generated by default will perform member-by-member byte-by -byte copy for built-in type members. For custom type members, you need to check whether the member implements move construction . If it is realized , call move construction , and if not , call copy construction .
  • Move assignment overloading has the same rules as above
  • If you provide move construction or move assignment, the compiler will not automatically provide copy construction and copy assignment.

The following code cannot be reflected in vs2013, and the above features can only be demonstrated under 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;
}

insert image description here

2. Keyword delete

deleteKeywords are used to explicitly disable some special member functions or operators to prevent them from being called or used in a specific context.

Using deletethe keyword, the following functions can be removed in the declaration of a class:

  1. Remove the default constructor:

    MyClass() = delete;
    

    This disables the default constructor, preventing no-argument creation of objects.

  2. Remove the copy constructor and copy assignment operator:

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

    This will prevent the copying of the object, that is, the copying of the object using the copy constructor and the copy assignment operator is prohibited.

  3. Remove the move constructor and move assignment operator:

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

    This will prevent the object's move semantics, that is, prohibit the use of move constructors and move assignment operators for object move operations.

  4. Delete the destructor:

    ~MyClass() = delete;
    

    This prevents the destruction of the object, that is, prohibits calling the destructor to free the memory of the object.

By using deletethe keyword, some potential errors or incorrect usage can be caught during compilation. For example, the compiler will generate an error if you try to copy or move a deleted function.

Example:

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

In the above example, a singleton class is implemented by removing the default constructor, copy constructor, and copy assignment operator. This prevents multiple instances from being created by duplication or copying. Any attempt to copy will be caught at compile time and generate an error.

In summary, C++11's deletekeywords provide developers with greater flexibility to explicitly delete certain functions to avoid misuse and errors in specific situations. This is a powerful feature in C++ that facilitates finer control over the behavior and semantics of classes.

3. final and override

In the C++11 standard, the keywords finaland overrideare used for class inheritance and virtual function rewriting. They provide an explicit way to control and mark inheritance relationships and function overrides.

3.1 final

finalKeywords are used to decorate classes, virtual functions or member functions, indicating that they cannot be inherited or overridden. Specifically:

  • When applied to a class, finalthe keyword indicates that the class cannot be inherited by other classes.
  • When applied to a virtual function, finalthe keyword indicates that the virtual function cannot be overridden by derived classes.
  • When applied to a member function, finalthe keyword indicates that the member function cannot be overridden in derived classes.

The following are finalexamples of using keywords:

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

overrideThe keyword is used to explicitly mark member functions in derived classes to indicate that they are overridden versions of virtual functions in the base class. Using overridekeywords can enhance the readability and maintainability of your code and help the compiler detect errors. If a function declaration in a derived class uses overridethe keyword, but does not override the virtual function in the base class, it will cause a compilation error.

The following are overrideexamples of using keywords:

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

Example with overridekeywords:

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

Note that prior to C++11, overriding of virtual functions was implicit and did not require the use of overridekeywords. However, using overridekeywords can provide more explicit semantics and better compile-time error detection.

Guess you like

Origin blog.csdn.net/ikun66666/article/details/131324978