learning
learning

Reputation: 11

Do I have to define a default constructor in C++?

In general, say I define my own constructor in such way:

class Numbers
{
public:
Numbers(int a, int b);
}

Would I have to:

  1. Define a new default constructor? I know the default constructor no longer exists once I define my own but I didn't know if it was necessarily / recommended to include one

  2. Do the parameters need to be included in the class? i.e. should I add:

class Numbers
{
private:
int ma;
int mb;
};

Thank you in advance!

Upvotes: 1

Views: 1487

Answers (4)

user17725758
user17725758

Reputation:

It depends on how you use your class Numbers.

Constructors can be used to :

  1. Allocate resources.
  2. Force the user of the class to initialize objects in a certain way.
  3. Check the arguments that will initialize the object and then to allow/avoid the creation of objects with a certain state (member variables).
  4. ...

For example, if you have a class date, the class could implement constructors that check the day, month and year we passed as arguments.

class date final {

public:

    constexpr date(const int d, const int m, const int y) : d(d), m(m), y(y) { 
    
        // Check if the object has a valid state (valid values)
        // e.g: Is d equal to 0? Is m greater than 12? If yes throw an exception 

    }

    constexpr auto day   () const noexcept { return d; }
    constexpr auto month () const noexcept { return m; }
    constexpr auto day   () const noexcept { return y; }

private:

    int d, m, y;

};

If the user of a class forgets to initialize an object, the compiler will give error. If the object is initialized with wrong values that can be checked during compilation, the compiler will give error, if it is not possible to check this during compilation, then an exception will be thrown during execution.

You can implement a default constructor for date if you can initialize a date object with valid and default values (the default concept in this case is subjective).

class date final {

public:

    constexpr date() noexcept : d(1), m(1), y(2001) { } // The first day of the current century, for example.
    constexpr date(const int d, const int m, const int y) : d(d), m(m), y(y) { 
    
        // Check if the object has a valid state (valid values)
        // e.g: Is d equal to 0? Is m greater than 12? If yes throw an exception 

    }

    constexpr auto day   () const noexcept { return d; }
    constexpr auto month () const noexcept { return m; }
    constexpr auto day   () const noexcept { return y; }

private:

    int d, m, y;

};

(The above example is similar to the one found in the book "Programming: Principles and Practice Using C++").

So, constructors and access modifiers allow you to implement a checked access to class members. We can use this to establish an invariant (conditions that must be met -that must be true-, e.g: the month of the date must be between [1:12] -inclusive-).

By answering your questions, use constructors when you need them and they are useful for what you are doing, when you implement constructors ask yourself why you do it.

Use the default constructor as your constructor, if you can provide default and valid values, implement a default constructor, so, if the user does not need to initialize the object with specific values, he can use the values provided by your constructor.

Sorry for my english.

I hope this will help you and I hope that someone can help me with my answer, I am also a beginner. xD

Edit :

An example of a "class" that you would implement without constructors and may not require an object-oriented approach.

struct vector2 {

    int x, y;

    static constexpr auto empty() noexcept { return vector2{ 0, 0 }; }

    constexpr auto operator+(const vector2& other) const noexcept { return vector2{ x + other.x, y + other.y }; }
    constexpr auto operator-(const vector2& other) const noexcept { return vector2{ x - other.x, y - other.y }; }

    constexpr auto operator==(const vector2& other) const noexcept { return x == other.x && y == other.y; }
    constexpr auto operator!=(const vector2& other) const noexcept { return !(*this == other); }

    constexpr auto is_empty() const noexcept { return *this == empty(); }

};

Or use operators as "free operators" (outside struct)

In this example, I do not use constructors, nor access modifiers because the "class" is simple and I have not established any invariant for the member variables (I could implement the "class" to ensure that the values of x and y are not negative, for example).

Upvotes: 0

rturrado
rturrado

Reputation: 8074

For very simple structs/classes you can always try to write them as aggregates. Basically:

  • don't use private or protected members.
  • don't user-provide constructors.

Then enjoy:

  • minimal declarations for your structs/classes.
  • simple direct-list-initialization.

[Demo]

#include <iostream>  // cout
#include <ostream>

struct Numbers  // minimal declaration
{
    int ma{};
    int mb{};
};

std::ostream& operator<<(std::ostream& os, const Numbers& ns)
{
    return os << "(" << ns.ma << ", " << ns.mb << ")";
}

int main()
{
    Numbers ns{10, 20};  // direct-list-initialization
    std::cout << ns << "\n";
}

Upvotes: 1

Tejas Gosavi
Tejas Gosavi

Reputation: 16

during compile-time 2 constructors are created automatically if given class contains no constructors.

1 - default constructor 2 - copy constructor

if you create one default constructor then constructor created automatically will be replaced by your constructor.

Upvotes: 0

Homer512
Homer512

Reputation: 13473

  1. That's up for you to decide. A default constructor can be handy and makes life easier in most cases. But if you want the users of your class to always provide numbers, that's fine, too.

  2. Yes, if you want attributes, you need to declare them. C++ doesn't magically deduce them from constructor arguments

Upvotes: 0

Related Questions