Can I call a constructor from another constructor (do constructor chaining) in C++?

前端 未结 15 2321
暖寄归人
暖寄归人 2020-11-22 01:27

As a C# developer I\'m used to running through constructors:

class Test {
    public Test() {
        DoSomething();         


        
相关标签:
15条回答
  • 2020-11-22 01:43

    C++11: Yes!

    C++11 and onwards has this same feature (called delegating constructors).

    The syntax is slightly different from C#:

    class Foo {
    public: 
      Foo(char x, int y) {}
      Foo(int y) : Foo('a', y) {}
    };
    

    C++03: No

    Unfortunately, there's no way to do this in C++03, but there are two ways of simulating this:

    1. You can combine two (or more) constructors via default parameters:

      class Foo {
      public:
        Foo(char x, int y=0);  // combines two constructors (char) and (char, int)
        // ...
      };
      
    2. Use an init method to share common code:

      class Foo {
      public:
        Foo(char x);
        Foo(char x, int y);
        // ...
      private:
        void init(char x, int y);
      };
      
      Foo::Foo(char x)
      {
        init(x, int(x) + 7);
        // ...
      }
      
      Foo::Foo(char x, int y)
      {
        init(x, y);
        // ...
      }
      
      void Foo::init(char x, int y)
      {
        // ...
      }
      

    See the C++FAQ entry for reference.

    0 讨论(0)
  • 2020-11-22 01:44

    This approach may work for some kinds of classes (when the assignment operator behaves 'well'):

    Foo::Foo()
    {
        // do what every Foo is needing
        ...
    }
    
    Foo::Foo(char x)
    {
        *this = Foo();
    
        // do the special things for a Foo with char
        ...
    }
    
    0 讨论(0)
  • 2020-11-22 01:45

    In C++11, a constructor can call another constructor overload:

    class Foo  {
         int d;         
    public:
        Foo  (int i) : d(i) {}
        Foo  () : Foo(42) {} //New to C++11
    };
    

    Additionally, members can be initialized like this as well.

    class Foo  {
         int d = 5;         
    public:
        Foo  (int i) : d(i) {}
    };
    

    This should eliminate the need to create the initialization helper method. And it is still recommended not calling any virtual functions in the constructors or destructors to avoid using any members that might not be initialized.

    0 讨论(0)
  • 2020-11-22 01:46

    I would propose the use of a private friend method which implements the application logic of the constructor and is the called by the various constructors. Here is an example:

    Assume we have a class called StreamArrayReader with some private fields:

    private:
        istream * in;
          // More private fields
    

    And we want to define the two constructors:

    public:
        StreamArrayReader(istream * in_stream);
        StreamArrayReader(char * filepath);
        // More constructors...
    

    Where the second one simply makes use of the first one (and of course we don't want to duplicate the implementation of the former). Ideally, one would like to do something like:

    StreamArrayReader::StreamArrayReader(istream * in_stream){
        // Implementation
    }
    
    StreamArrayReader::StreamArrayReader(char * filepath) {
        ifstream instream;
        instream.open(filepath);
        StreamArrayReader(&instream);
        instream.close();
    }
    

    However, this is not allowed in C++. For that reason, we may define a private friend method as follows which implements what the first constructor is supposed to do:

    private:
      friend void init_stream_array_reader(StreamArrayReader *o, istream * is);
    

    Now this method (because it's a friend) has access to the private fields of o. Then, the first constructor becomes:

    StreamArrayReader::StreamArrayReader(istream * is) {
        init_stream_array_reader(this, is);
    }
    

    Note that this does not create multiple copies for the newly created copies. The second one becomes:

    StreamArrayReader::StreamArrayReader(char * filepath) {
        ifstream instream;
        instream.open(filepath);
        init_stream_array_reader(this, &instream);
        instream.close();
    }
    

    That is, instead of having one constructor calling another, both call a private friend!

    0 讨论(0)
  • 2020-11-22 01:50

    I believe you can call a constructor from a constructor. It will compile and run. I recently saw someone do this and it ran on both Windows and Linux.

    It just doesn't do what you want. The inner constructor will construct a temporary local object which gets deleted once the outer constructor returns. They would have to be different constructors as well or you would create a recursive call.

    Ref: https://isocpp.org/wiki/faq/ctors#init-methods

    0 讨论(0)
  • 2020-11-22 01:53

    Would be more easy to test, than decide :) Try this:

    #include <iostream>
    
    class A {
    public:
        A( int a) : m_a(a) {
            std::cout << "A::Ctor" << std::endl;    
        }
        ~A() {
            std::cout << "A::dtor" << std::endl;    
        }
    public:
        int m_a;
    };
    
    class B : public A {
    public:
        B( int a, int b) : m_b(b), A(a) {}
    public:
        int m_b;
    };
    
    int main() {
        B b(9, 6);
        std::cout << "Test constructor delegation a = " << b.m_a << "; b = " << b.m_b << std::endl;    
        return 0;
    }
    

    and compile it with 98 std: g++ main.cpp -std=c++98 -o test_1

    you will see:

    A::Ctor
    Test constructor delegation a = 9; b = 6
    A::dtor
    

    so :)

    0 讨论(0)
提交回复
热议问题