Constructors and Destructors in C++

原文地址:http://www.cprogramming.com/tutorial/constructor_destructor_ordering.html

Constructors and Destructors in C++

By Andrei Milea

Constructor and Destructor Order

The process of creating and deleting objects in C++ is not a trivial task. Every time an instance of a  class is created the constructor method is called. The constructor has the same name as the class and it doesn't return any type, while the destructor's name it's defined in the same way, but with a '~' in front: 

class String
{

public:

String() //constructor with no arguments
    :str(NULL),
    size(0)
{

}

String(int size) //constructor with one argument
    :str(NULL),
    size(size)

{
    str = new char[size];
}


~String() //destructor
{
    delete [] str;
};

private:

    char *str;

    int size;

}
Even if a class is not equipped with a constructor, the compiler will generate code for one, called theimplicit default constructor. This will typically call the default constructors for all class members, if the class is using virtual methods it is used toinitialize the pointer to the virtual table, and, in class hierarchies, it calls the constructors of the base classes. Both constructors in the above example use  initialization lists in order to initialize the members of the class. 

The construction order of the members is the order in which they are defined, and for this reason the same order should be preserved in the initialization list to avoid confusion. 

To master developing and debugging C++ applications, more insight is required regarding the way constructors and destructors work. Some problems arise when we are dealing with class hierarchies. Let's take a look at the following example where class B is inherited from class A:
class A
{

public:

A(int m,int n)
    :m(m),
    n(n)
{
    cout<<"constructor A"<<m<<n;
};

~A()
{

};

private:

int m;
int n;

};


class B : public A

{

public:

B()
    :b(5) //error : default constructor to initialize A is not found
{
    cout<<"constructor B"<<b;
}

~B()
{};

private:

int b;

};


int main()
{

B x;
return 0;

};
When we create an object of type B, the A part of the B object must be initialized and since we provide a constructor for class A, the compiler will not create an implicit default constructor.This code will fail to compile because there is no default constructor for class A to be called. To fix this we could provide a default constructor in class A or explicitly call the existing constructor of A in the initialization list of the B's constructor:
B()
:A(3,4),
b(5)
{
    cout<<"constructor B"<<b;
}
Notice that we needed to call the constructor of A before doing any initialization in B, since the order of construction starts with the base class and ends with the most derived class.

Never Use Virtual Methods in Constructors or Destructors

A side effect of this behavior is that you should avoid calling virtual functions in a class's constructor (or destructor). The problem is that if a base class makes a virtual function call implemented by the derived class, that function may be implemented in terms of members that have not yet been initialized (think of the pain that would cause!). C++ solves this problem by treating the object as if it were the type of the base class, during the base class constructor, but this defeats the whole purpose of calling a virtual function in a constructor. Destruction, by the way, works in the same way. If you're interested, Scott Meyers has a  very nice writeup of this principle taken from his book  Effective C++: 55 Specific Ways to Improve Your Programs and Designs 

The destruction order in derived objects goes in exactly the reverse order of construction: first the destructors of the most derived classes are called and then the destructor of the base classes.

Virtual Destructors

To build an object the constructor must be of the same type as the object and because of this a constructor cannot be a virtual function.But the same thing does not apply to destructors. A destructor can be defined as virtual or even pure virtual. You would use a virtual destructor if you ever expect a derived class to be destroyed through a pointer to the base class. This will ensure that the destructor of the most derived classes will get called:
A* b1 = new B;
delete b1;
If A does not have a virtual destructor, deleting b1 through a pointer of type A will merely invoke A's destructor. To enforce the calling of B's destructor in this case we must have specified A's destructor as virtual:
virtual ~A();
It is a good idea to use a virtual destructor in any class that will be used as an  interface (i.e., that has any other virtual method). If your class has no virtual methods, you may not want to declare the destructor virtual because doing so will require the addition of a vtable pointer. 

The destructor is called every time an object goes out of scope or when explicitly deleted by the programmer(using operator delete). The order in which local objects are implicitly deleted when the scope they are defined ends is the reverse order of their creation:
void f()
{
    string a(.some text.);
    string b = a;
    string c;
    c = b;
}
At the end of function f the destructors of objects c, b, a (in this order) are called and the same memory is deallocated three times causing undefined and wrong behavior.  Deleting an object more than one time is a serious error. To avoid this issue, class string must be provided with a copy constructor and a copy assignment operator which will allocate storage and copy the members by values. The same order of construction/destruction applies for temporary objects that are used in expressions or passed as parameters by value. However, the programmer is usually not concerned with temporary objects since they are managed by the C++ compiler. 

Unlike local objects,  static objects are constructed only the first time their definition is reached and destroyed at the end of the program. 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值