将一个object的内容作为另一个class object的初值的三种情况:
(a)明确的初始化操作
class X{...}
X x;
X xx=x;
(b)作为函数的参数
extern void foo(X x);
void bar()
{
X xx;
//以xx作为foo()第一个参数的初值(不明显的初始化操作)
foo(xx);
}
X foo_bar()
{
X xx;
return xx;
}
如果明确定义了copy constructor,则发生上述三种情况时,会调用这些copy constructor。
X::x(const X& x);
Y::y(cons tY& y, int = 0) ;
如果没有提供一个明确的(explicit)copy constructor,会把每一个内建的或派生的data member(一个指针或数组)的值从某个object拷贝一份到另一个object中,着被称为 Default Memberwise Initialization 。不过这不会拷贝其中的member class object,而是以递归的方式施行memberwise initialization。
(a)default member wiseinitialization
#include<iostream>
#include<stdlib.h>
using namespace std;
class String{
public:
//...没有explicit copy constructor
String(char* s):str(s){
for(len=0;s[len]!='\0';++len);
};
private:
friend ostream& operator<< (ostream& os,const String& s);
char *str;
int len;
};
ostream& operator<< (ostream& os,const String& s)
{
os<<"str:"<<s.str<<", "<<"len:"<<s.len;
//os<<"yes"<<endl;
return os;
}
int main()
{
String noun("book");
cout<<"noun:"<<noun<<endl;
String verb=noun;
cout<<"verb:"<<verb<<endl;
system("pause");
return 0;
}
(b)递归方式的Member Initialization
#include<iostream>
#include<stdlib.h>
using namespace std;
class String{
public:
//...没有explicit copy constructor
String(char* s):str(s){
for(len=0;s[len]!='\0';++len);
};
private:
friend ostream& operator<< (ostream& os,const String& s);
char *str;
int len;
};
class Word{
public:
Word(int o,String s):_occurs(o),_word(s){}
void print();
private:
int _occurs;
String _word;
};
void Word::print(){
cout<<_word<<endl;
}
ostream& operator<< (ostream& os,const String& s)
{
os<<"str:"<<s.str<<", "<<"len:"<<s.len;
return os;
}
int main()
{
String noun("book");
Word w1(5,noun);
Word w2=w1;
cout<<"w1:";
w1.print();
cout<<"w2:";
w2.print();
system("pause");
return 0;
}
★Default constructors和copy constructors在必要的时候才由编译器产生出来
二、bitwise copy senmantics
(a)不需要合成default copy constructor
class Word{
public:
word(const char*);
~word(){delete []str;}
private:
int cnt;
char *str;
}
上述情况不需要合成默认的复制构造函数,因为其展现了“default copy semantics”,但可能发生内存泄露,
(b)必须合成一个copy constructor以便调用member class String的 copy constructor
//一个被合成的copyconstructor
//伪码
inline Word::word(const Word& wd)
{
str.String::String(wd.str);
cnt=wd.cnt;
}
被合成的copy constrcutor中,整数、指针、数组等nonclass members也都会被复制。
二、不要bitwise copy semantics的四种情况
1.当class 内含一个member object而后者的class声明有一个copy constructor时(无论明确声明或被编译器合成)
2.当class继承自一个base class而后者存在有一个copy constructor(无论明确声明或被编译器合成)
3.当class声明了一个或多个virtual class
4.当class派生自一个继承串链,其中有一个或多个是virtual base class时
前两种情况,编译器必须把member或base class 的copy constructor安插到被合成的constructor中。
三、重新设定virtual table 指针
■增加一个virtual funcation table(vtbl),内含每一个有作用的virtual function的地址
■将一个指向virtual function table的指针(vtpr)安插在每一个class object内
当编译器导入一个vptr到class之中,该class就不在展现bitwise semantics,编译器需要合成一个copy constructor,以求将vptr初始化。
class ZooAnimal{
public:
ZooAnimal();
virtual ZooAnimal();
virtual void animate();
virtual void draw();
private:
//一些数据。。。
};
class Bear:publicZooAnimal{
public:
Bear();
void animate();//未写明,为virtual
void draw();//未写明,为virtual
virtual void dance();
private:
//所需一些数据...
};
同类型的class object作为初值,都可用“bitwise copy semantics”
Bear yogi;
Bear winnie = yogi;
此时yogi被default Bear constructor初始化,在constructor中,yogi的vptrvptr被指向Bear class的virtual table
ZooAnimal franny = yogi
franny的vptr不可以被设定指向Bear class的virtual table。
void draw(const ZooAnimal& zoey){zoey.draw();}
void foo()
{
ZooAnimal franny=yogi;
draw(yogi); //调用Bear::draw();
draw(franny);//调用ZooAnimal::draw();
}
上例说明合成出来的ZooAnimal的copy constructor会明确设定object的vptr指向ZooAnimal class的virtual table,而不是直接拷贝。
四、处理virtual base class subobject
一个virtual base class的存在会使bitwise copy semantics无效。
class Reccoon: public virtual ZooAnimal{
public:
Reccoonn(){}
Reccoonn(int val){}
private:
//必要的数据
};
class RedPanda:public Raccoon{
public:
RedPanda(){}
RedPanda(int val){}
private:
//....
};
Raccoon rocky;
Raccoon little_critter = rocky;
此时,编译器必须合成一个copy constructor,安插一些码来设定virtual base class pointer/offset