由C++复制控制想到

来源:互联网 发布:mp5游戏下载软件 编辑:程序博客网 时间:2024/06/15 19:17

C++复制控制想起

 

一、什么是初始化、赋值。

它说初始化是创建变量并给变量赋初值,而赋值是擦除对象的当前值并用新值代替。     

二、C++的初始化、赋值。

C++中进行初始化时必须使用初始化列表才叫初始化。而不是在构造函数中对其赋值。那么,初始化列表和直接赋值有什么本质区别?那下我们来看代码:

使用赋值操作符来初始化成员其实是一个伪初始化的过程。在上面的过程中,在进入A()的函数体之前,idname都就已经调用了它们各自的默认构造函数进行初始化,而在构造函数A()的函数体中又会再次调用operator = 来进行赋值。但是内置类型没有这个过程,所以对于内置类型,使用初始化成员列表或在构造函数体内对其进行赋值没什么大的区别。

    这一次idname就只分别调用了它们各自的复制构造函数一次,而免去了多余了那一次对operator = 的调用.对于非内置类型来说,这就提高了对象的初始化效率。虽然对于内置类型来说这没有什么大的不同,但为了保持一致性,通常也把它们放在初始化成员列表中进行初始化。

另外 = 操作符所表示的意思也不总是赋值,在对象定义声明时使用操作符 = 对象调用的就是其复制构造函数而不是operator =。

 

三、explicit为何物。

      从《c++ primer》中的一句话说起:“某些版本将参数为一个string的构造函数定义为explicit。如果构造函数是显式的,则初始化失败;如果构造函数不是显式的,则初始化成功”。这里说的显式即是使用explicit来声明这个构造函数,而不是显式则不使用explicit。下面来看一点代码:

显式使用explicit

    

在①、②中这时我们的右值是一个C-style的字符串,而左值是一个类。当不使用explicit 时自然是不会出现这样的情况的,可以顺利的通过编译并正常的执行。。C++作为一种强类型的语言,这里并没有显式的进行类型转换,那么一定是发生了隐式的类型转换。编译器知道传入的值是字符串,而需要的右值是Sales_item类型,但它同时也知道调用Sales_item的构造函数将字符串转换成一个合适的Sales_item

而加上explicit后,就会出现上面程序中所示的错误,那么现在为什么会是这样的情况呢?

这个问题得从explicit说起。在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。只要定义了任何一个需要参数的构造函数,编译器就不会为你生成默认构造函数。

就这个问题而言,在这条语句中:Sales_item item = "abc.dsljf"; 若没有在构造函数中使用explicit这个关键字,那么这个隐式转换的过程如下:

        

    我们并没有显式的指定一个复制构造函数,这里是通过默认的复制构造函数实现这个转换过程。而当我们使用了explicit后,编译器就不允许进行隐式转换。这个时候,上面的过程不能进行。会报出如下错误:

 

    当我们使用③,即直接构造形式时不会存在上述过程,那么就可以顺利通过。我们使用explicit的目的就是强调类型的匹配!不能随意的进行隐式转换。

explicit使用注意事项:explicit 关键字只能用于类内部的构造函数声明上,并且explicit 关键字作用于单个参数的构造函数,当然,多个参数时,除首个参数外的其它参数具有默认值除外。

那么再看下面的例子(感谢网友提供)

按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面所示:

但是有的时候可能会不需要这种隐式转换,如下:

下面两种写法比较正常:

下面两种写法就比较疑惑了:

s4 s5 分别把一个int型和char型,隐式转换成了分配若干字节的空字符串,容易令人误解。

为了避免这种错误的发生,我们可以声明显示的转换,使用explicit 关键字:

加上explicit,就抑制了String ( int n )的隐式转换,

下面两种写法仍然正确:

下面两种写法就不允许了:

因此,某些时候,explicit 可以有效得防止构造函数的隐式转换带来的错误或者误解

explicit只对构造函数起作用,用来抑制隐式转换。如:  

 

 当调用Function(2)的时候,2会隐式转换为A类型。这种情况常常不是程序员想要的结果,所以,要避免之,就可以这样写:  

   

 这样,当调用Function(2)的时候,编译器会给出错误信息(除非Function有个以int为参数的重载形式),这就避免了在程序员毫不知情的情况下出现错误。

 

四、现在来说复复制和赋值

我们可以通过直接形式来初始化一个类:

  

当然也可以通过复制的方式进行:

或者:

2)Sales_item tmp(temp2);    总之我们需要明白,复制构造函数就是:       Sales_item(const Sales_itemp& it);    只要是实现了在初始化时,通过对象来赋值即是调用的复制构造函数。


 

而赋值则是:

 

一般来说需要复制构造函数也需要operator=。应当将二者看为一个整体。   

原创粉丝点击