拷贝函数的正常使用

来源:互联网 发布:剑灵蒂法捏脸数据图 编辑:程序博客网 时间:2024/05/02 06:05

C++面向对象的程序语言,到处存在继承体系:整理一下使用构造函数与析构函数注意事项:

 

Item1: 编译器可以隐式自动生成的函数包括四个:

defatult constructor:默认构造函数

copy constructor:拷贝构造函数

copy assignment operator:拷贝赋值函数

destructor:析构函数

编译器可以自动生成,并不代表一定会生成,只有在用户未手动声明对应函数时,编译器可以自动生成相应的函数。

classBase{}; // 四个编译器全部自动生成

classBase

{

        Base();

};             // 编译器生成除default constructor外的三个函数

 

Item2: 不想使用编译器自动生成的函数应该明确告诉编译器

       如果想要实现object禁止拷贝功能:

classBase   // F1

{

public:

    Base(){}

    ~Base(){}

private:

    Base(constBase&);

    Base&operator=(constBase&);

};

 

 

classBase   // F2

{

public:

    Base(){}

    ~Base(){}

    Base(constBase&)=delete;

    Base&operator=(constBase&)=delete;

};

 

 

classBase   // F3

{

public:

    Base(){}

    ~Base(){}

private:

    Base(constBase&)=delete;

    Base&operator=(constBase&)=delete;

}

 

Q1:为什么拷贝函数设置为私有函数?

A1:因为私有函数外部无法访问,可以达到无法创建object的目的。

 

Q2:为什么拷贝函数只有声明而没有实现?

A2:因为万事都有例外,友元函数可以冲破private,所以只有声明没有实现,

从而可以达到调用拷贝函数提醒报错的目的。

 

Q3:除了私有化拷贝函数还有别的方法实现吗?

A3:有,利用C++11的特性,使用keyword:delete。

 

 

Item3: member data initializtion of object(member initialization list)

       Baseclass的初始化要在Derived class前初始化,成员变量的初始化要在初始化列表中按照声明顺序进行初始化。


 

       因为只调用一次copy constructor function效率比先调用一次defaultconstructor function后再调用一次copy assignment operator效率要高的多。所有建议使用member initializtion list对member data 进行初始化。    

classPeople
{
public:
    People(conststd::stringname,constintage);
    virtual~People();
private:
    std::stringm_str_name;
    intm_int_age;
};
People::People(conststd::stringname,constintage)
    :m_str_name(name),m_int_age(age){}
People::~People(){}
 
classHoney:publicPeople
{
public:
    Honey(conststd::stringname,constintage);
    ~Honey();
};
 
Honey::Honey(conststd::stringname,constintage)
    :People(name,age){}
Honey::~Honey(){}

 

Item4: virtual destructor的正确使用

       如果一个class准备作为base class 使用,将destructor设置为virtual destructor是一个受欢迎的行为。因为在创建derived class时候,可以自动销毁base class资源。

       如果一个class不准备作为base class使用,将destructor设置为virtual destructor是一不好的想法。因为虚函数意味着使用更多的内存。

 

Item5: copy all data(local data and base data)

       拷贝一个对象的所有数据包括:本地所有数据成员,以及调用基类中适当的拷贝函数。

       如果为一个类增加了一个成员,则就应该更新所有拷贝函数。确保所有数据成员都可以正确拷贝。

       不要企图用一个拷贝函数调用另一个拷贝函数完成相应的功能。重复的代码可以提取出来作为第三个函数(private:init();)

   

classPeople

{

public:

    People()=default;

    virtual~People(){}

};

 

classHoney:publicPeople

{

public:

    Honey(conststd::stringname,constintage);

    ~Honey();

private:

    std::stringm_str_name;

    intm_int_age;   

};

 

Honey::Honey(conststd::stringname,constintage)

    :People(),m_str_name(name),m_int_age(age){}

Honey::~Honey(){}

 

Item6: construtors and destrcutors不应该调用virtual function

       虚函数的实现依赖于vptr,vptr存在于base class 中。

不要在constructor和destructor中调用virtual function,因为不会出现多态现象,为什么?因为在constructor中调用virtual function时,derived object还没有创建完成,只会出现base class中的行为。在析构函数中调用virtual function当寻找vptr时derived class已经被析构完成,则仍为base class中的行为。

如果拷贝函数与构造函数存在重复的代码可以将公共的代码提取出来放入第三个函数(private function)。

classPeople
{
public:
    People(){init("people",30);}
    virtual~People(){}
private:
    virtualvoidinit(std::stringname,constintage)=0;
    virtualvoiddestroy()=0;
};
 
classHoney:publicPeople
{
public:
    Honey(){init("honey",28);}
    ~Honey();
private:
    std::stringm_str_name;
    intm_int_age;
    voidinit(std::stringname,constintage)override;
    voiddestroy()override;
};
 
voidHoney::init(std::stringname,constintage)
{
    m_str_name=name;
    m_int_age=age;
}
voidHoney::destroy(){}

 

Item7: exceptions不应该出现有constructor中

对于异常的结果处理分为三种:

第一种:抑制异常使用程序继续运行。

第二种:终止程序。

第三种:提供常规异常处理函数(需要用户参与时)。

       destructor应该永不引发异常,因为如果在destructor中引发异常意味着内存泄漏。如果调用可能会发生异常的函数,则destructor应该捕获所有异常,然后抑制异常或者终止程序。一般来说,抑制异常比程序提前终止或产生未定义行为更可取。因为一个应用程序必须可以保证抑制异常后还能正常可靠的运行。

       建议使用智能指针代替常规指针,使用vector代替数组。

 

Item8: assignment operator should return refernce to*this

assignment operator是一个右结合运算符

int x, y, z;

x = (y = (z = 15));

classPeople

{

public:

    People()=default;

    People&operator=(constPeople&rhs);

private:

    std::stringm_str_name;

};

 

People&People::operator=(constPeople&rhs)

{

    m_str_name=rhs.m_str_name;

    return*this;   

}

 

 

Item9:在asiignment中处理assignment to self

assignment to self是由于别名造成的(多个指针指向同一块内存,多个引用与同一个变量进行绑定)。

classPeople

{

public:

    People()=default;

    People&operator=(constPeople&rhs);

private:

    std::stringm_str_name;

};

 

People&People::operator=(constPeople&rhs)

{

    if(this==&rhs)    return*this; //自赋值安全

    People*p=this;                  //异常安全

    this=newPeople(rhs);

deletep;

 

    return*this;   

}

 

如果可以做到上面九点,我想应该可以安全高效的处理好对象之间的拷贝关系了。

参考effective c++后的个人意见,仅供参考,如果有什么忽略的或者好的意见,请大家不吝赐教。

(ps :多年工作以来,一直都看别人的文章,以后本人会整理更多想法与大家分享:大家可以一直讨论,一起学习,一直进步。邮箱:wangqing10520@sina.com)。

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 2个月宝宝不拉大便怎么办 论文已查重了要下载查重报告怎么办 华为畅享7手机媒体音量小怎么办 杂志投稿投到了假的网站怎么办 支付宝骗了5万多怎么办 微信转账到银行卡被骗了怎么办 给对方转账到银行卡疑似被骗怎么办 谷歌邮箱收不到邮件了怎么办 我在微信上做兼职被骗了钱怎么办 要是微信里面做兼职被骗了怎么办 在打离婚管斯死亡赔常金怎么办 编辑部回复我文章没有被录用怎么办 父亲死后教师资格被别人顶替怎么办 刚发的论文影响因子变化了怎么办 奥鹏毕业论文过了提交时间了怎么办 手机电池被拿出来后时间不准怎么办 高中的孩子与同学相处不好怎么办 孩子在幼儿园不敢和老师说话怎么办 注册过万方医学网忘了用户名怎么办 狗咬了没破皮没出血有点疼怎么办 狗咬了没出血肿起来了怎么办 广州已经过了幼儿园报名时间怎么办 大专学费没交学校开始查了怎么办 如果申请留学的本科成绩不够怎么办 硕士读了三年无法毕业怎么办啊 孩子在美国读研读不下去怎么办? 在地割草中过失死亡法律^怎么办 高中毕业申请国外大学没录取怎么办 英国研究生老师没给写推荐信怎么办 申请悉尼大学博士奖学金被拒怎么办 硕士延迟毕业但被博士录取怎么办 考完初级职称还是不会做账怎么办 美国留学生在中国办日本签证怎么办 留学雅思过了gpa低怎么办澳洲 护士电子化注册用户名忘记了怎么办 护士电子化注册证书编码错误怎么办 澳洲预科上半学期成绩不达标怎么办 美国大学绩点不够怎么办学习证明 研一想换导师导师不答应怎么办 日本留学在留下来不想去了怎么办 加拿大工签3年到期了怎么办