Search code examples
c++construction

Other way to prohibit a certain C++ class construction except than declaring the constructor private?


Say I have a class with some const reference member variable and I would like to forbid a certain type of construction. So I would declare the according constructor private. Of course, a constructor must initialise all const reference member variables of the class. Doing so, however, results in odd looking code:

class A {
};

class B {
  B(const A& a): host(a) {}
private:
  B():host(A()) {}   // This is ugly and not needed !!
  const A& host;
};

Is there another way to prohibit a certain construction type except than declaring the constructor private? I do not want to let the compiler write a constructor for me.


Solution

  • Simply don't define this:

    B():host(A()) {}   // This is ugly and not needed !!
    

    That is, the following should do what you want to do:

    class B {
      B(const A& a): host(a) {}
    private:
      //B():host(A()) {}   // This is ugly and not needed !!
      const A& host;
    };
    

    The idea is if you've defined a constructor that takes parameter(s), then the default constructor is not generated by the compiler. That means, instances of the above class cannot be default created!

     B b1; //error - needs default constructor which doesn't exist!
     B b2(a); //ok - only way to create an instance!
    

    C++11 solution

    In C++11, you can explicity tell the compiler not to generate a particular constructor as:

    struct B
    {
         B(const A &a) {}
    
         B() = delete;      //disable
    };
    

    Not only that. There is more to it, as explained below:

    Now the interesting part

    You can also selectively disable constructor(s) for selected types which makes delete more interesting. Consider this,

    struct A
    {
           A (int) {}
    };
    

    Object of this class can be created not only with int argument, but any type which implicitly converts to int. For example,

    A a1(10);  //ok
    A a2('x'); //ok - char can convert to int implicitly
    
    B b; 
    A a3(b); //ok - assume b provides user-defined conversion to int
    

    Now suppose, for whatever reason, I don't want the users of class A to create objects with char or class B , which fortunately or unfortunately can implicitly convert to int, then you can disable them as:

    struct A
    {
         A(int) {}
         A(char) = delete;      //disable
         A(const B&) = delete;  //disable
    };
    

    Now here you go:

    A a1(10);  //ok
    A a2('x'); //error
    
    B b; 
    A a3(b); //error - assume (even if) b provides user-defined conversion to int
    

    Online Demo : http://ideone.com/EQl5R

    The error messages are very clear:

    prog.cpp:9:5: error: deleted function 'A::A(char)'
    prog.cpp:10:5: error: deleted function 'A::A(const B&)'