电子说
C++在编译器会给我们默认创建一个缺省的构造方法: 如下代码:
class Father {
public:
string name = "father";
int age = 45;
void print() {
cout << "name:" << name << " age:" << age << endl;
}
};
class Son :public Father {
public:
string sex = "male";
};
void extendsTest::mainTest()
{
Son son;
son.print();
};
运行结果:name:father age:45
可以看到虽然我们没有明确声明构造方法,但是依然可以调用无参构造方法。这就是因为 编译器自动给我们创建了一个无参构造方法 、
如果类定义了自己的构造方法后(包括无参和有残),编译器就不会给我们创建了 ,看下面代码:
class Father {
public:
Father() {
cout << "Father:" << name << endl;
}
string name = "father";
int age = 45;
void print() {
cout << "name:" << name << " age:" << age << endl;
}
};
class Son :public Father {
public:
Son(){
cout << "Son:" << name << endl;
}
string sex = "male";
};
void extendsTest::mainTest()
{
Son son;
son.print();
};
打印结果:
Father:father
Son:father
name:father age:45
从上面代码也可以看出C++编译器会默认优先调用父类的构造方法,再调用子类的构造方法,
这点和java中是有区别的,java会从子类开始依次调用父类的构造方法,然后回溯子类的构造方法
所以为了保证对象的顺利创建,需要保证父类的构造方法是有效的。 如下代码:
class Father {
public:
Father(string _name):name(_name){
cout << "Father:" << name << endl;
}
string name = "father";
int age = 45;
};
此时父类中创建了一个有参构造方法,前面说过,此时编译器不会创建默认的无参构造方法,则需要保证在其子类中有初始化父类的操作:即调用父类有参构造方法。 如下代码:
class Son :public Father {
public:
Son(string name):Father(name) {
cout << "Son:" << name << endl;
}
string sex = "male";
};
void extendsTest::mainTest()
{
Son son1("myName");
};
结果:
Father:myName
Son:myName
析构函数用来释放当前对象使用到的内存空间,当对象跳出其作用域范围后就会执行析构函数( 除非是有智能指针出现循环引用的情况,无法释放,导致泄露 )。 C++中析构函数和构造函数相反,会 优先调用子类的析构函数再调用父类的析构函数 。 如下代码:
class Father {
public:
~Father() {
cout << "~Father"<< endl;
}
string name = "father";
int age = 45;
};
class Son :public Father {
public:
~Son() {
cout << "~Son" << endl;
}
string sex = "male";
};
void extendsTest::mainTest()
{
Son son;
};
运行结果:
~Son
~Father
C++中拷贝构造函数格式:
class Complex {
public:
double real, imag;
Complex(double _real, double _imag):
real(_real),imag(_imag)
{
cout << "real:" << real << " imag:" << imag << endl;
}
void print() {
cout << "real:" << real << " imag:" << imag << endl;
}
Complex(Complex& c) {
real = c.real+1; imag = c.imag+1;
}
};
void extendsTest::mainTest()
{
Complex c1(1.0, 2.0);
Complex c2(c1);
c2.print();
};
打印结果:
real:1 imag:2
real:2 imag:3
拷贝构造函数和构造方法类似, C++编译器会给我们提供默认的拷贝构造函数 。 将上面代码的拷贝构造函数删除后:
class Complex {
public:
double real, imag;
Complex(double _real, double _imag):
real(_real),imag(_imag)
{
cout << "real:" << real << " imag:" << imag << endl;
}
void print() {
cout << "real:" << real << " imag:" << imag << endl;
}
};
void extendsTest::mainTest()
{
Complex c1(1.0, 2.0);
Complex c2(c1);
c2.print();
};
依然可以执行拷贝构造,此时c2使用了默认拷贝构造函数进行赋值。
拷贝构造的几种调用形式:
1.当用一个对象去初始化同类的另一个对象时
Complex c2(c1);
Complex c2 = c1;
这两天语句是等价的。但是要 注意此时Complex c2 = c1是一个初始化语句,并非一个赋值语句。赋值语句是一个已经初始化后的变量 。 如下:
Complex c1, c2; c1 = c2 ;
c1=c2;
赋值语句不会触发拷贝构造 。
2.当对象作为一个函数形参时,此时也会触发对象的拷贝构造
class Complex {
public:
double real, imag;
Complex(double _real, double _imag):
real(_real),imag(_imag)
{
cout << "real:" << real << " imag:" << imag << endl;
}
Complex(Complex& c) {
real = c.real+1; imag = c.imag+1;
cout << "complex copy" << endl;
}
};
void func(Complex c) {
cout << "real:" << c.real << " imag:" << c.imag << endl;
}
void extendsTest::mainTest()
{
Complex c(1.0,2.0);
func(c);
};
运行结果:
real:1 imag:2
complex copy
real:2 imag:3
可以看到运行结果触发了Complex的拷贝构造 以对象作为函数的形参,在函数被调用时,生成的形参要用复制构造函数初始化,这会带来时间上的开销。 如果用对象的引用而不是对象作为形参,就没有这个问题了 。
void func(Complex& c) {
cout << "real:" << c.real << " imag:" << c.imag << endl;
}
但是以引用作为形参有一定的风险,因为这种情况下如果形参的值发生改变,实参的值也会跟着改变。 最好的方法就是将函数形参声明为const类型的引用 。
void func(const Complex& c) {
cout << "real:" << c.real << " imag:" << c.imag << endl;
}
3.对象作为函数返回值返回时,也会触发拷贝构造。
Complex func() {
Complex c(1.0, 2.0);
return c;
}
void extendsTest::mainTest()
{
cout << func().real << endl;
};
结果:
real:1 imag:2
complex copy
2
可以看到此时func函数中的return c处会触发一次拷贝构造,并将拷贝后的对象返回。 这点通过函数hack过程也可以看出来:此处call方法执行的是拷贝构造方法
全部0条评论
快来发表一下你的评论吧 !