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

C++11 新的类功能

1.默认成员函数

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

最后重要的是前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关键字可以提供更明确的语义和更好的编译时错误检测。

本文链接:https://my.lmcjl.com/post/2810.html

展开阅读全文

4 评论

留下您的评论.