千里马肝
class A{ public: A(int i) : m_i(i){} int m_i; }; int main(){ A a = 0; a = 10; }
分别说说吧: 1. A a = 0; 首先, compiler认为这样写是不符合规矩的, 因为A = A才是正常行为。 但是她并不放弃, 通过搜索, 发现A可以根据一个int构造, 同时这个A(int i)没有用explicit修饰过。 那么A a = 0; 这样的一句话随即转变成: A tmp(0); A a = tmp; 需要说明的是, A a = tmp是调用的copy ctor, 虽然class A中并没有, 但是通常不写copy ctor的话, compiler都会生成一个memberwise assignment操作性质的ctor, 底层实现通常会以memcpy进行。
2. a = 10; 首先, 这样同ctor的情况一样, compiler无法直接进行操作。 类推, 等同于代码: A tmp(10); a = tmp; 需要注意的是, a = tmp是调用的assignment操作, 同ctor一样,我们自己不写, 编译器同样进行 memberwise assignment操作。
3. fn(A a) 同样, fn(10)也是不对的, 但是"按照惯例", 呵呵, 会有: A tmp(10); fn(tmp);
另外, 为你解惑: copy ctor的写法只能是T::T(const T &); 而assignment的写法可以多变, 即任意. 以T为例, 可以有 T &operator = (int n); 也可有 T &operator = (const char *); 当然, 你要确认如此的定义是对T而言有意义.
然后, 上述a = tmp, 即调用的默认的、标准的、自动生成的T &operator = (const T &). 开销是会有一个临时的A tmp生成, 然后memcpy. 但如果你自已写了T &operator = (int n), 那么a = 10即意味着a.m_i = 10. 当然, 以开销而言要视你的T &operator = (int n)是否为inline了.
对于explicit, 当修饰explicit A(int i) : m_i(i){}, 那么即告诉compiler不要在私底下做那么多的转换动作. 而且自动生成如A tmp(0)这样的东西是我们不想要的, 因为某些情况下自动转换这种行为是错误的.
最后, 相关此类问题, 还有一个话题, 即class A可以有operator int(), 会在 fn(int n){} A a(3); fn(a) 起到魔术般的作用. 关于这个, 留给你自己看看书吧:)
最后,祝学习C++的路上一帆风顺。Good luck~ 
|