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

c++ primer(第五版)笔记 第十三章(1) 拷贝控制

2014-12-25 23:08 330 查看
// 类的拷贝控制操作
// 拷贝构造函数		copy constructor
// 如果一个构造函数,第一个参数是自身类型的引用,且任何额外参数都有默认值,如果是非引用类型,则会调用拷贝构造函数,无限循环。。。
// 通常拷贝构造函数	,不应该是一个 explicit的,好多时候需要类型转换
// 如果没有定义拷贝构造函数,编译器会合成一个拷贝构造函数
// 通常第一个参数是 const 类型
// 拷贝构造函数,将参数对象的所有非 static 成员依次拷贝到正在创建的对象中

// 拷贝初始化 和 直接初始化
// 直接初始化时,是要求编译器使用普通函数的匹配规则来选择合适的构造函数
// 拷贝初始化时,要求编译器将右侧运算对象拷贝的到正在创建的对象中,如果需要还会进行类型转换
// 将一个对象作为实参传递给一个非引用类型的形参,如函数调用
// 从一个返回非引用类型的函数返回一个对象,如函数返回
// 用花括号列表初始化一个数组中的元素或一个聚合类中的成员

// 拷贝赋值运算符	copy-assignment operator
// 如果未定义,自动合成,必须是一个成员函数,运算符的左侧运算子值绑定到隐式的this参数,右侧的运算子为显式参数传递

// 析构函数			destructor

// 无返回值,不接受参数,销毁该对象的非 static 成员
// 自动调用:
// 1.当变量离开其作用域
// 2.对象被销毁时,其成员被销毁
// 3.容器被销毁时,其元素被销毁
// 4.对于动态分配的对象,当指向它的指针应用delete运算符时被销毁
// 5.对于临时对象,当创建它的完整表达式结束时被销毁

// 控制函数的规律:
// 需要析构的类也需要拷贝和赋值操作,如析构时 delete 构造函数一个 new 的动态内存,此类如果使用合成拷贝构造和拷贝赋值运算符,可以使多个对象指向同一内存地址以及多次释放同一指针的未定义错误
// 如果需要拷贝操作也需要赋值操作,反之亦然,但不一定需要析构

// 阻止拷贝
// 将拷贝构造和拷贝赋值运算定义为删除函数(deleted function)“=delete”
// c++11前通过将拷贝构造和拷贝赋值运算定义为private,来阻止
// 不能删除析构,如果一个类或其某个成员删除了析构,编译器禁止定义该类的变量或临时变量,因为无法销毁对象,虽然可以动态分配该类型的对象,但无法释放
// 定义删除的合成拷贝控制成员:
// 1.如果类的某个成员的析构是删除的或不可访问的(private),则类的合成析构,合成拷贝构造被定义为删除的
// 2.如果类的某个成员的拷贝构造是删除的或不可访问的(private),则类的合成拷贝构造被定义为删除的
// 3.如果类的某个成员的拷贝赋值运算是删除的或不可访问的(private)或类有一个const 或 引用成员,则类的合成拷贝赋值运算被定义为删除的
// 4.如果类的某个成员的析构是删除的或不可访问的(private),或类有一个引用成员没有初始化器,或是有一个 const 成员没有类内初始化器且其类型未显式定义默认构造函数,则类的默认构造被定义为删除的

// 显式生成合成的成员函数
// 仅用于具有合成版本的成员,默认构造或拷贝控制成员 “=default”

#include<iostream>
#include<vector>
#include<memory>

class X{
public:
X( int n = 99) : a( n){
std::cout << "X" << std::endl;
}
X( const X& y): a( y.a){
std::cout << "X( const X&)" << std::endl;
}
X& operator=( const X& y){
a = y.a;
std::cout << "X& operator=( const X&)" << std::endl;
}
~X(){
std::cout << "~X" << std::endl;
}

int a;
};

void printra(X &x){
std::cout << "x.a:" << x.a << std::endl;
}

void printca(X x){
std::cout << "x.a:" << x.a << std::endl;
}

//为每个对象生成随机
class numbered{
public:
static unsigned int sn;

//默认构造
numbered() : mysn( ++sn){
std::cout << "numbered:" << std::endl;
}
//自增拷贝构造
numbered( const numbered&) : mysn( ++sn){
std::cout << "numbered( const numbered&):" << std::endl;
}
//赋值是运算
numbered& operator=( const numbered&){
std::cout << "operator=( const numbered&)" << std::endl;
return *this;
}
//合成拷贝构造函数
// numbered( const numbered& tmp){
// std::cout << "numbered( const numbered&):" << std::endl;
// mysn = tmp.mysn;
// }

unsigned int mysn;
};
unsigned int numbered::sn = 0;
void f( const numbered& s) { std::cout << s.mysn << std::endl;}

//雇员
class Employee{
public:
static std::size_t sn;

Employee() : id( ++sn), name(""){};
Employee( std::string str) : id( ++sn), name(str){};
Employee( const Employee&) = delete;
Employee& operator=( const Employee& e) = delete;
~Employee(){};

std::size_t id;
std::string name;
};

int main(){
X x{88};
std::cout << "x.a:" << x.a << std::endl;
{
X y;
std::cout << "y.a:" << y.a << std::endl;
y = x;
std::cout << "y.a:" << y.a << std::endl;
}
X z{x};
std::cout << "z.a:" << z.a << std::endl;
std::cout << "=========A=========" << std::endl;
printra( z);
std::cout << "=========B=========" << std::endl;
printca( z);
std::cout << "=========C=========" << std::endl;
std::vector< X> vx(1);
std::cout << "=========D=========" << vx.begin()->a << std::endl;
vx.push_back(z);
std::cout << "=========E=========" << std::endl;
vx.pop_back();
std::cout << "=========F=========" << std::endl;
std::shared_ptr< X> sx;
std::cout << "=========G=========" << std::endl;
std::shared_ptr< X> sx1( new X);
std::cout << "=========H=========" << std::endl;
std::shared_ptr< X> sx2( X);
std::cout << "=========I=========" << std::endl;

numbered A, B = A, C = B;	//A构造,BC拷贝构造,f(x)拷贝构造
f( A);
f( B);
f( C);
// 合成拷贝控制输出:
// 1
// 1
// 1
// 自增拷贝控制输出:
// 3
// 4
// 5
// f( const numbered s) :f(const &x)不发生拷贝
// 1
// 2
// 3
return 1;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: