您的位置:首页 > 编程语言 > C语言/C++

杂货边角(16):C++11之后,类的所有构造函数

2018-02-12 17:07 375 查看
C++类声明中,编译器会默认帮助程序员生成一些他们未定义的成员函数,这样的函数被称为“默认函数”,这包括了以下一些自定义类型的成员函数:

1.构造函数;

2.拷贝构造函数

3.拷贝赋值函数(operator= (const Class & T) )

4.移动构造函数

5.移动拷贝赋值函数(operator= (Class&& T) )

6.析构函数

但是程序员一旦在类的定义中显式地声明上述构造函数的任何一种,则编译器将不会在为该类定义该种类下的默认版本。最常见的便是一旦声明了带参构造函数,则同时也需要程序员自己提供无参构造函数,否则该类将不存在无参构造函数。(但不是说定义了构造函数,系统不提供拷贝构造函数、移动构造函数等,即上述1、2、 3等之间彼此不冲突)。

#include <string>
#include <iostream>
#include <memory>
#include <vector>
#include <string.h>

using namespace std;

class CMyString {
private:
char * buf;
int len;

private:
void copy(const char* s) {
buf = new char[len+1];
memcpy(buf, s, len);
buf[len] = '\0';
}

public:
CMyString() {
std::cout << "non-param constructor" << std::endl;

buf = nullptr;
len = 0;
}

CMyString(const char* str = nullptr) {
if (str == nullptr) {
std::cout << "one-param constructor" << std::endl;

buf = nullptr;
len = 0;
}
else {
std::cout << "one-param constructor: " << str << std::endl;
len = strlen(str);
copy(str);
}
}

CMyString(const CMyString& str) {                               //拷贝构造函数
std::cout << "copy constructor: " << str.buf << std::endl;

len = str.len;
copy(str.buf);
}

CMyString(CMyString&& str) {
std::cout << "move constructor: " << str.buf << std::endl;  //移动构造函数

//也可以直接使用std::move

len = str.len;
buf = str.buf;

str.len = 0;
str.buf = nullptr;
}

CMyString& operator=(const CMyString& str) {
std::cout << "copy and assignment func: " << str.buf << std::endl;   //拷贝赋值函数

if (&str != this) {
if (buf != nullptr) {
delete[] buf;
buf = nullptr;
}

len = str.len;
copy(str.buf);
}

return *this;
}

CMyString& operator=(CMyString&& str) {
std::cout << "move and assignment func: " << str.buf << std::endl; //移动赋值函数

if (this != &str) {

if (buf != nullptr) {
delete[] buf;
buf = nullptr;
}

len = str.len;
buf = str.buf;
str.len = 0;
str.buf = nullptr;
}

return *this;
}

~CMyString() {
if (buf == nullptr)
{
std::cout << "destructor" << std::endl;
}
else
{
std::cout << "destructor: " << buf << std::endl;
delete[] buf;
buf = nullptr;
}
}

void print() {
if (buf != nullptr)
std::cout << buf << std::endl;
else
std::cout << "buf is null" << std::endl;
}

};

void func1(CMyString str) {

}

CMyString func2() {
CMyString s("34");
std::cout << "Resource from " << __func__ << ": " << hex << &s << endl;
return s;
}

void func3(CMyString && str) {
CMyString tmp = std::move(str);  //move constructor
//CMyString tmp = str;   //copy constructor这是因为虽然str初始声明为右值引用,但一旦
//占据表达式右值的位置时,则该右值引用的语义将变成不折不扣的左值,除非用move强制声明
}

void test0() {
CMyString s1("12");

func1(s1); //对象str尚未初始化,会调用拷贝构造函数

CMyString s2(func2()); // 对象s2尚未初始化,会产生临时对象,调用移动构造函数
std::cout << "Resource from " << __func__ << ": " << std::hex << &s2 << endl;
//这一步存在一步编译器优化,比移动语义更加激进的优化方式,直接将func2()返回的temp对象
//的指针,直接赋给s2,故这一步实际并没有调用任何构造函数RVO return value optimization
//CMyString s2(std::move(func2())); //这样写则会体现出移动语义的鸠占鹊巢,存在临时对象的构造和析构

CMyString s3 = "56";//对象s3尚未初始化,虽然是有'=6',但是其实依旧调用带参构造函数

s3 = s1; //对象s3已初始化,会调用拷贝赋值函数

func3(static_cast<CMyString&&> (s1) );
s1.print();

cout << "now comes to the destructor part:" << endl;
}

void test1() {
CMyString s4 = "78";
std::vector<CMyString> v1;
//v1.push_back(s4);
v1.push_back(std::move(s4)); // 对象尚未初始化,会调用移动构造函数

std::cout << "v1 vector-container list:\n";
for (auto& str : v1)
str.print();

std::vector<CMyString> v2;
v2 = std::move(v1);

std::cout << "v1 content:\n";
for (auto& str : v1)
str.print();

std::cout << "v2 content:\n";
for (auto& str : v2)
str.print();
}

void test2() {

CMyString s5 = "9";
s5 = func2(); // 对象s5已初始化, 会产生临时对象,调用移动赋值函数
}

int main(void)
{
std::cout << "begin test0()" << std::endl;
test0();
std::cout << std::endl;

std::cout << "begin test1()" << std::endl;
test1();
std::cout << std::endl;

std::cout << "begin test2()" << std::endl;
test2();

return 0;
}






内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++11 构造函数
相关文章推荐