对象的构造、析构、拷贝构造
2011-04-21 10:28
176 查看
这是一道外企的C++笔试题,要求写出结果并分析:
#include <iostream.h>
class A
{
public:
static int num;
A() {cout<<num++;}
~A(){cout<<num--;}
};
int A::num=0;
class B: public A
{
public:
B(){cout<<num++;}
~B(){cout<<num--;}
A f(A a) {return a;}
};
int main()
{
A a;
B b;
b.f(b);
return 0;
}
输出结果是 0123210-1-2,下面对于每次输出给出分析:
0 在A a, 调用了A的构造函数,输出0(注意对num使用的是后减)
1 在B b, 先调用A的构造函数,输出1
2 在B b, 再调用B的构造函数,输出2
在b.f(b), 首先传参时,A temp_a = (A)b, 这里通过拷贝构造函数生成temp_a ,再将 temp_a 赋给 f中的a,也是通过拷贝构造
数, 所以这里没有输出,即没有构造函数的调用,大家不要认为生成对象都要经过构造函数。
3 f返回时, temp_a 析构,调用A的析构函数 输出3
2 f返回时, a析构,调用A的析构函数 输出2
在return a,虽然main中没有定义变量接收 f 的返回值,但是实际上 f 返回的时候生成了一个临时值,如temp_a
1 f返回后, 返回的temp_a 析构,调用A的析构函数 输出1
0 main返回 b析构,先调用B的析构函数, 输出0
-1 main返回 b析构,再调用A的析构函数, 输出-1
-2 main返回 a析构,调用A的析构函数, 输出-2
构造函数的调用顺序: 先基类的构造函数,后派生类的构造函数。
析构函数的调用顺序: 先派生类的析构函数,后基类的析构函数。
先构造的对象后析构,后构造的对象先析构。
拷贝构造函数被调用的三种情况:
1.程序中需要建立一个新的对象,并用另一个同类对象对它初始化的时候。 例如: A a; A a_1 = a;
2.当函数的参数为类的对象的时候。 例如 :
void f(A a){}
void main()
{
A a_1;
f(a_1);
}
3.当函数的返回值类型为类的对象的时候。 例如:
A f()
{
A a_1;
return a_1;
}
void main()
{
A a;
a = f();
}
当自己定义的类中没有定义拷贝构造函数的时候,系统在需要调用拷贝构造函数的时候自动调用默认的拷贝构造函数。
这时候需要注意一个问题:
当类的成员变量中有一个指针变量,而在生成类对象后,对象的这个指针变量指向了一块堆空间,这时候,如果使用这个对象去初始化一个新的对象的时候,调用了默认的拷贝构造函数。这样,两个对象的指针都指向了同一块对空间,如果类的析构函数里对这个指针进行了delete操作,将导致这两个对象析构的时候,同一块堆空间被释放两次,进而出现错误。
这其实就是传说中的对象的深拷贝和浅拷贝的问题,要解决这个问题,就要定义自己的拷贝构造函数,在复制对象中指向堆空间的指针的时候,申请新的堆空间,并进行内容的复制。
从今天开始我要做一个自由的人,喂马、劈柴,神游世界。
#include <iostream.h>
class A
{
public:
static int num;
A() {cout<<num++;}
~A(){cout<<num--;}
};
int A::num=0;
class B: public A
{
public:
B(){cout<<num++;}
~B(){cout<<num--;}
A f(A a) {return a;}
};
int main()
{
A a;
B b;
b.f(b);
return 0;
}
输出结果是 0123210-1-2,下面对于每次输出给出分析:
0 在A a, 调用了A的构造函数,输出0(注意对num使用的是后减)
1 在B b, 先调用A的构造函数,输出1
2 在B b, 再调用B的构造函数,输出2
在b.f(b), 首先传参时,A temp_a = (A)b, 这里通过拷贝构造函数生成temp_a ,再将 temp_a 赋给 f中的a,也是通过拷贝构造
数, 所以这里没有输出,即没有构造函数的调用,大家不要认为生成对象都要经过构造函数。
3 f返回时, temp_a 析构,调用A的析构函数 输出3
2 f返回时, a析构,调用A的析构函数 输出2
在return a,虽然main中没有定义变量接收 f 的返回值,但是实际上 f 返回的时候生成了一个临时值,如temp_a
1 f返回后, 返回的temp_a 析构,调用A的析构函数 输出1
0 main返回 b析构,先调用B的析构函数, 输出0
-1 main返回 b析构,再调用A的析构函数, 输出-1
-2 main返回 a析构,调用A的析构函数, 输出-2
构造函数的调用顺序: 先基类的构造函数,后派生类的构造函数。
析构函数的调用顺序: 先派生类的析构函数,后基类的析构函数。
先构造的对象后析构,后构造的对象先析构。
拷贝构造函数被调用的三种情况:
1.程序中需要建立一个新的对象,并用另一个同类对象对它初始化的时候。 例如: A a; A a_1 = a;
2.当函数的参数为类的对象的时候。 例如 :
void f(A a){}
void main()
{
A a_1;
f(a_1);
}
3.当函数的返回值类型为类的对象的时候。 例如:
A f()
{
A a_1;
return a_1;
}
void main()
{
A a;
a = f();
}
当自己定义的类中没有定义拷贝构造函数的时候,系统在需要调用拷贝构造函数的时候自动调用默认的拷贝构造函数。
这时候需要注意一个问题:
当类的成员变量中有一个指针变量,而在生成类对象后,对象的这个指针变量指向了一块堆空间,这时候,如果使用这个对象去初始化一个新的对象的时候,调用了默认的拷贝构造函数。这样,两个对象的指针都指向了同一块对空间,如果类的析构函数里对这个指针进行了delete操作,将导致这两个对象析构的时候,同一块堆空间被释放两次,进而出现错误。
这其实就是传说中的对象的深拷贝和浅拷贝的问题,要解决这个问题,就要定义自己的拷贝构造函数,在复制对象中指向堆空间的指针的时候,申请新的堆空间,并进行内容的复制。
从今天开始我要做一个自由的人,喂马、劈柴,神游世界。
相关文章推荐
- 深入探索C++对象模型之五 --- 析构、构造、拷贝语意学
- 【C++】深度探索C++对象模型之构造、析构、拷贝语意学
- [读书笔记] 深入探索C++对象模型-第五章-构造、析构、拷贝语义学(上)
- object构造、拷贝构造、析构、临时对象
- 深度探索C++对象模型:5.构造、析构、拷贝语意学
- 深度探索C++对象模型复习和学习 第五章:构造、析构、拷贝、语意学
- [读书笔记] 深入探索C++对象模型-第五章-构造、析构、拷贝语义学(下)
- C++对象模型 第五章 构造、析构、拷贝语意学
- 深度探索C++对象模型 第五章 构造、析构、拷贝语意学
- C++对象模型 ch5 构造 析构 拷贝语义学
- [读书笔记] 深入探索C++对象模型-第五章-构造、析构、拷贝语义学(中)
- c++子类对象构造与析构的顺序对多态性的影响
- 子函数中定义静态类的对象(还不错哦)(注意区别,析构与构造在子函数中的行为)
- 对象的构造和析构
- 6.1 对象的构造与析构
- 经典笔题--重写字符串类 (构造,拷贝,析构,重载)
- 构造、析构、继承对对象的影响
- 如何定义和实现新的GObject之对象构造和析构
- C++对象的构造、赋值和析构
- Lession 9 构造、析构、拷贝