开发者

Why would someone provide an empty default constructor for a class?

class complex
{
  float x,y;
public:
  complex(){} //constructor with no arguments //what is use of giving such constructor
    complex(float z){x=y=z;}//constructor with 1 argument.
    complex(float real,float imag)
    {x=real;y=imag;}
    friend complex sum(complex,complex);
     friend void show(complex);
};

complex sum(complex c1,complex c2)
{
  c开发者_StackOverflow社区omplex c3;
  c3.x=c1.x+c2.x;
  c3.y=c1.y+c2.y;
  return (c3);
}

void show (complex c)
{
  cout<<c.x<<"+j"<<c.y<<"\n";
}
int main()
{
  complex p,q,r;
  p=complex(2.5,3.9);
  q=complex(1.6,2.5);
  r=sum(p,q);

  cout<<"p=";show(p);
  cout<<"q=";show(q);
  cout<<"r=";show(r);
  return 0;
}


When you declare a class without any constructors, the compiler provides a default constructor (on demand) that default-initializes the members. (Note that default-initialization on built-ins such as float does nothing). However, once you define any constructor for the class, the default constructor is no longer automatically provided. Hence you must define your own default constructor if you still want one.


This is a codeified and corrected version of @user470379's answer

Consider the empty class:

class complex
{
    float x,y;
};

The compiler actually generates several functions for this class for you, even if they are not declared. The compiler generated functions make the class really look like this:

class complex
{
    float x,y;
public:
    complex(); //Compiler generated functions
    complex(const complex&);
    complex& operator=(const complex&);
    ~complex();
};

Now, you take your complex class, and you add your constructor taking a float. When you do this, you tell C++ that you do not want the compiler provided default constructor:

class complex
{
    float x,y;
public:
    // complex(); //No longer generated
    //Don't forget explicit here unless you want implicit conversions
    //from `float`
    explicit complex(float z) {x=y=z;} //User defined constructor
    /////////////////////////////////////////////////////////
    //Compiler generated functions
    complex(const complex&);  //Note copy constructor and copy assignment
                              //operator are still generated.
    complex& operator=(const complex&);
    ~complex();
};

Now, whenever anyone wants a complex they must provide the float parameter. For example, the following code is now illegal:

int main()
{
    complex c; //ERROR! No default constructor available.
    complex g(4.2f); //Ok; float parameter specified.
}

If you want your user to be able to just construct a complex without supplying the float parameter, you must then explicitly create the constructor:

class complex
{
    float x,y;
public:
    complex() {} //Allow default construction of `complex` objects.
    //Don't forget explicit here unless you want implicit conversions
    //from `float`
    explicit complex(float z) {x=y=z;}
    ////////////////////////////////////////////////////////
    complex(const complex&);  //Compiler generated functions
    complex& operator=(const complex&);
    ~complex();
};

Now the user can default-construct a complex object anywhere they please.


Because some programmers haven't upgraded their habits to modern standards.

Back in the old C days (pre C-99), one had to declare variables at the top of a block, and thus declaration and initialisation were frequently separated.

In modern C++, there is barely ever a good reason not to declare and initialize in the same statement.

As a result, it should be an exception and not the rule to provide a default constructor.


While I agree with the fact that default constructors should be frowned upon if there is no canonical meaning to them (complex numbers should have a default constructor that makes them zero, to mimic built in types semantics), there are a few scenarios where they are mandatory. Quite a few standard library constructs mandate default constructible objects, especially iterators and containers' value types (at least for some methods: resize for instance).

Sometimes, you may want objects (or are forced by the standard to want) to have a "null" state, which is only reachable by a default constructor. Then you have to write safe bool idioms, use smart pointers and pimpl idioms, etc. This can be good, or not.

I agree, it is not good practice to add the complexity of null states (and the errors they can induce) to objects which don't need them, but sometimes, you are forced to.

For the record, complex classes should look like:

struct complex
{
    // Allow default initialization, and standard embedding
    // of real numbers in complex numbers
    complex(float real = 0., float imag = 0.) 
        : real(real), imag(imag) 
    {}

    float real, imag; // no need for privacy here
};

// Operators are defined outside the class
complex operator+(complex x, complex y) 
{
    return complex(x.real + y.real, x.imag + y.imag);
}

// etc

std::ostream& operator<<(std::ostream& os, complex x)
{
    return os << x.real << " + i" << x.imag;
}

Note that since complex is a POD type, you should even be able to do complex x = { 2., 3. }; and have them zero-initialized for you in static arrays.


Working with the C++ Standard Library usually requries your classes to have no-arg constructor (like in: vector<complex> vc(6);).

Creating arrays either stack-allocated (complex arcmpl[20];) or dynamically allocated (complex * dynarcmplx = new complex[n];) as well calls no-arg constructors.

As it was said before, if you define any constructor for your class, you have no more (compiler generated no-arg) “default constructor” and in this case if you want to write something like I mentioned above, you should provide your own no-arg constructor.


Providing an empty default constructor(private) is necessary in those cases when you don't want an object of the class in the whole program.

For e.g. the class given below will have a compiler generated default empty constructor as a public member. As a result, you can make an object of such a class.

class test1
{
public:
int a;
};
int main()
{
test1 var; //compiles without an error.
}

However, if you want to stop anyone from constructing an object of the class, you can add an empty constructor as a private member. For e.g.

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

int main()
{
test2 var; // This will give an error
}

abc.cpp: In function âint main()â: abc.cpp:10:9: error: âtest2::test2()â is private within this context test2 var; // This will give an error ^~~ abc.cpp:3:3: note: declared private here test2(){} ^~~~~

You'll get an error if you try to run the above program because by design the 'test2' class is not supposed to have an object.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜