简体   繁体   中英

Why can't one ctor call another ctor to initialize the object

class Foo {

 public:
  Foo() { Foo(1)}
  Foo(int x, int y = 0):i(x) {}
 private:
  int i;
}

Can anybody give me some reasonas about can I do this? If not why?

Because the language specification doesn't allow it. Just the way the language is. Very annoying if you're used to Java or other languages that allow it. However, you get used to it after a while. All languages have their quirks, this is just one of C++'s. I'm sure the writers of the specs have their reasons.

Best way around this I've found is to make a common initialization function and have both constructors call that.

Something like this:

class Foo {
public:
    Foo() {initialize(1);}
    Foo(int nX) { initialize(nx); }

private:
    void initialize(int nx) { x=nx; }
    int x;
};

It's a language design choice.

A constructor is a one time (per-object) operation that creates a new object in uninitialized memory. Only one constructor can be called for an object, once it has completed the object's lifetime begins and no other constructor can be called or resumed on that object.

At the other end of its life a destructor can only (validly) be called once per object and as soon as the destructor is entered the object's lifetime is over.

A prinicipal reason for this is to make explicit when an object destructor will be run and what state it can expect the object to be in.

If a class constructor completes successfully then it's destructor will be called, otherwise the object's lifetime has never begun and the destructor will not be called. This guarantee can be important when an object acquires resources in its constructor that need to be released in its destructor. If the resource acquisition fails then the constructor will usually be made to fail; if the destructor ran anyway it might attempt to release an resource that had never been successfully acquired.

If you allow constructors to call each other it may not be clear if a calling or a called constructor is responsible for the resource. For example, if the calling constructor fails after the called constructor returns, should the destructor run? The called constructor may have acquired something that needs releasing or perhaps that was what caused the calling construtor to fail and the destructor shouldn't be called because the resource handle was never valid.

For simplicity of the destruction rules it is simpler if each object is created by a single constructor and - if created successfully - destroyed by a single destructor.

Note that in C++11 a constructor will be able delegate to a different constructor, but there are limitations that don't really relax the principal of one construction per object. (The prinicipal constructor can forward to a target constructor, but if it does it must not name anything else (base classes or members) in its initializer list. These will be initialized by the target constructor, once the target constructor returns the body of the prinicipal constructor will complete (further initialization). It is not possible to re-construct any bases or members, although it allows you to share constructor code between constuctors.)

You cant do this. See section 10.3: http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.3 . You can try to do it but doing so will construct a new temp object (not this) and be destroyed once control moves on.

What you can do however is to create a private function that initializes variables, one that your default constructor or a parameterized constructor can both call.

There is a really hideous hack I have seen used to call another ctor. It uses the placement new operation on the this pointer. erk

Like this:

Class::Class(int x) : x_(x) {}
Class::Class() {
    new (this) Class(0);
}
Class::Class(const Class &other) : x_(other.x_) {}
Class& operator=(const Class &other) {
    new (this) Class(other);
    return *this;
}

Note that I am not recommending this, and I don't know what horrible effects it might have on C++ structures like virtual base classes, etc. But I expect that there are some.

Although as per standards vendors are free to implement data binding in their own ways, if we consider the most popular implementation: this pointer, we can see a reason why this can't be implemented.

Assume you have a class:

class A
{
    public:
    A(){}
    A(int a){}
} ;

With the this pointer implementation, this class would look something like:

class A
{
    public:
    A(A *this){}
    A(A *this,int a){}
} ;

Typically you would create objects like this:

A ob ;

Now when compiler sees this, it allocates memory for this and passes the address of this allocated memory block to the constructor of A which then constructs the object. It would try to do the same every time for each constructor called.

Now when you try calling a constructor within another constructor, instead of allocating new memory the compiler should pass the current objects this. Hence inconsistency!

Then another reason which i see is that even though you might want to call a constructor within another, u would still want a constructor to call default constructors for all the objects within the class. Now if one constructor were to call another, the default construction should happen for the first constructor and not for the subsequent one's. Implementing this behavior means that there would be several permutations which need to be handled. If not, then degraded performance as each constructor would default construct all the objects enclosed.

This is what i can think of as possible reasons for this behavior and do not have any standards to support.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM