目录
类的新功能
默认成员函数
示例
类成员变量初始化
强制生成默认函数的关键字default
禁止生成默认函数的关键字delete
类的新功能
默认成员函数
- 构造函数
- 析构函数
- 拷贝构造函数
- 拷贝赋值重载
- 取地址重载
- const取地址重载
C++11在原先的6个默认成员函数的基础上,新增了2个:【移动构造函数】和【移动赋值运算符重载】
默认移动构造的生成条件
条件1:开发者不显示实现移动构造函数;
条件2:析构函数、拷贝构造、赋值运算符重载函数任意一个都没有显示实现;
当同时满足条件1与条件2,编译器自动生成移动构造函数;
移动构造函数的规则
- 移动构造函数对于内置类型成员按字节序完成值拷贝;
- 移动构造函数对于自定义类型成员调用自定义类型的移动构造,若自定义类型成员没有移动构造,便调用其拷贝构造;
默认移动赋值的生成条件
条件1:开发者不显示实现移动赋值函数;
条件2:析构函数、拷贝构造、赋值运算符重载函数任意一个都没有显示实现;
当同时满足条件1与条件2,编译器自动生成移动赋值函数;
移动赋值函数的规则
- 移动赋值函数对于内置类型成员直接赋值;
- 移动赋值函数对于自定义类型成员调用自定义类型的移动赋值,若自定义类型成员没有移动赋值,便调用其赋值运算符重载函数;
开发者显示提供移动构造与移动赋值,编译器不再自动生成移动构造与移动赋值;
示例
namespace RightReference
{
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);
}
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
// 拷贝构造
string(const string& s)
:_str(nullptr)
{
cout << "string(const string& s) --- 深拷贝" << endl;
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
//移动构造--右值
string(string&& s)
{
cout << "string(string&& s) -- 移动拷贝" << endl;
swap(s);
}
// 拷贝赋值
string& operator=(const string& s)
{
cout << "string& operator=(const string& s) --- 深拷贝" << endl;
string tmp(s);
swap(tmp);
return *this;
}
// 移动赋值--右值
string& operator=(string&& s)
{
cout << "string& operator=(string&& s) -- 移动拷贝" << endl;
swap(s);
return *this;
}
~string()
{
delete[] _str;
_str = nullptr;
}
char& operator[](size_t pos)
{
assert(pos < _size);
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)
{
push_back(ch);
return *this;
}
const char* c_str() const
{
return _str;
}
private:
char* _str = nullptr;
size_t _size = 0;
size_t _capacity = 0;
};
}
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()
{}*/
private:
RightReference::string _name;
int _age;
};
int main()
{
Person s1;
Person s2 = s1;
Person s3 = std::move(s1);
Person s4;
s4 = std::move(s2);
return 0;
}
类成员变量初始化
默认生成的构造函数,对于自定义类型的成员会调用其构造函数进行初始化,但并不会对内置类型的成员进行处理;于是C++11支持非静态成员变量在声明时进行初始化赋值,默认生成的构造函数会使用这些缺省值对成员进行初始化;比如:
class Person
{
public:
//...
private:
//非静态成员变量,可以在成员声明时给缺省值
RightReference::string _name = "peter";
int _age = 20;
static int _n; //静态成员变量不能给缺省值
};
强制生成默认函数的关键字default
C++11可以更好的控制要使用的默认成员函数,假设在某些情况下需要使用某个默认成员函数,但是因为某些原因导致无法生成这个默认成员函数,这时可以使用default关键字强制生成某个默认成员函数;
例如:我们提供了拷贝构造函数,就不会生成默认移动构造了,那么我们可以使用default关键字强制生成移动构造;
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(Person&& p) = default;
private:
RightReference::string _name;
int _age;
};
int main()
{
Person s1;
Person s2 = s1;
Person s3 = std::move(s1);
return 0;
}
例如:Person类中只实现了拷贝构造函数,没有实现构造函数,由于拷贝构造函数本身也是构造函数,默认构造不再自动生成;
class Person
{
public:
//拷贝构造函数
Person(const Person& p)
:_name(p._name)
,_age(p._age)
{}
private:
RightReference::string _name;
int _age;
};
int main()
{
Person s1;//error 没有合适的默认构造函数使用
return 0;
}
此时可以使用default关键字强制生成默认的构造函数,如下:
class Person
{
public:
Person() = default;
//拷贝构造函数
Person(const Person& p)
:_name(p._name)
,_age(p._age)
{}
private:
RightReference::string _name;
int _age;
};
int main()
{
Person s1;//error 没有合适的默认构造函数使用
return 0;
}
禁止生成默认函数的关键字delete
C++98中,不期望某个类的对象被拷贝,得限制默认的拷贝构造函数的生成,一般的处理方式为将拷贝构造函数只声明不实现并且将此声明置于私有,如此外部调用时便会报错;
class Person
{
public:
Person(const char* name=" ",int age=0)
:_name(name)
,_age(age)
{}
private:
//拷贝构造函数
Person(const Person& p);
RightReference::string _name;
int _age;
};
int main()
{
Person s1("Linda", 20);
Person s2 = s1;//error
return 0;
}
C++中只需要在拷贝构造函数的声明中加上=delete即可,该语法指示编译器不再生成拷贝构造函数的默认版本,称=delete修饰的函数为删除函数;
class Person
{
public:
Person(const char* name=" ",int age=0)
:_name(name)
,_age(age)
{}
//拷贝构造函数
Person(const Person& p) = delete;
private:
RightReference::string _name;
int _age;
};
int main()
{
Person s1("Linda", 20);
Person s2 = s1;//error 尝试引用已删除的函数
return 0;
}
欢迎大家批评指正,博主会持续输出优质内容,谢谢各位观众老爷观看,码字画图不易,希望大家给个一键三连支持~ 你的支持是我创作的不竭动力~