Search code examples
c++classobjectinheritanceconstructor

How to define default constructor and user-defined constructor in the same line?


In my university class we are messing around with inheritance, though my professor's code confused me and seemed to be a little off.

class Circle
{
  protected:
    double radius;
  public:
    Circle(double = 1.0);
    double calcval();
};

Circle::Circle(double r)
{
  radius = r;
}

Here she is creating a default constructor within the class then creating a separate user-defined constructor outside of the class. When I initially saw this I thought there has to be a way to do this more efficiently and in return take up less space, making the code more readable.

After some searching online I found some resources at which I tried, though I am still getting some errors. Here is the constructors for class "Circle" which I tried.

class Circle
{
    protected:
        double radius;

    public:
        double calcVal();

        Circle(double r = 1.0) : radius(r) {}
};

Is this correct? I am trying to make the default constructor set radius = 1.0 and have a constructor that sets radius = to 'r', the user input.

We also have another derived class "Cylinder" which I tried doing something similar but received errors.

Here is my professor's implementation.

class Cylinder : public Circle
{
  protected:
    double length;
    double volume;
  public:       
    Cylinder(double r, double len);
    double calcval();
};

Cylinder::Cylinder(double r, double len){
    length =len;
    this->radius =r;
}

Then here is what I attempted.

class Cylinder : public Circle
{
    private:
        double length;
        double volume;
    public:
        double calcVal();

        Cylinder(double r, double len) : length(len) this->radius(r) {}
};

However, I get an error on the beginning of "this", which says "expected a "{"."

How, if possible, would I create a default constructor and user-defined constructor in the same line for readability and cleaner code? Thank you so much for reading.

My overall implementation for your convenience. :)

class Circle
{
    protected:
        double radius;

    public:
        double calcVal();

        Circle(double r = 1.0) : radius(r) {}
};

double Circle::calcVal()
{
    return (PI * (radius * radius));
}

class Cylinder : public Circle
{
    private:
        double length;
        double volume;
    public:
        double calcVal();

        Cylinder(double r, double len) : length(len) this->radius(r) {}
};

double Cylinder::calcVal()
{
    return (length * PI * (r * r));
}

Solution

  • Here she is creating a default constructor within the class then creating a separate user-defined constructor outside of the class.

    No, she is declaring the default constructor inside the class's declaration, and then defining the body of that constructor outside of the class declaration. This is perfectly legal and correct code.

    I am still getting some errors

    That is because you have mistakes in your code.

    Here is the constructors for class "Circle" which I tried ... Is this correct?

    In that example, yes.

    We also have another derived class "Cylinder" which I tried doing something similar but received errors ... Then here is what I attempted ... However, I get an error on the beginning of "this", which says "expected a "{"."

    Since radius is a member of Circle, you should let Circle's constructor initialize radius. Don't do that in your derived Cylinder's constructor. But, you are not calling Circle's constructor yourself, so the compiler will call it for you, passing in its default argument value.

    You are also missing a , in your Cylinder's constructor member initialization list, which is a syntax error.

    Try this instead:

    Cylinder(double r, double len) : Circle(r), length(len) {}
    

    Now, that being said, there are some other things worth pointing out in your code.

    Your Cylinder class has a volume member that is never initialized or used, so it should be removed completely.

    Inside of Cylinder::calcVal(), r is undefined. It is a local variable in the Circle and Cylinder constructors only. You need to use the radius member instead (just like how Circle::calcVal() does, and how Cylinder::calcVal() is using the length member instead of the len constructor argument), eg:

    return (length * PI * (radius * radius));
    

    You are declaring double calcVal(); in both classes, but Circle::calcVal() is not marked as virtual, so Cylinder::calcVal() will not override it. If you were to ever make a Circle*/Circle& refer to a Cylinder object and then call calcVal() on that, only Circle::calcVal() would be called, not Cylinder::calcVal(). So, make Circle::calcVal() be virtual, eg:

    virtual double calcVal();
    

    And for good measure, Cylinder should then mark its calcVal() as override:

    double calcVal() override;
    

    Since you want to reduce complexity in your classes, you can inline calcVal() in both classes, eg:

    class Circle
    {
        protected:
            double radius;
    
        public:
            virtual double calcVal() { return (PI * (radius * radius)); }
    
            Circle(double r = 1.0) : radius(r) {}
    };
    
    class Cylinder : public Circle
    {
        private:
            double length;
    
        public:
            double calcVal() override { return (length * PI * (radius * radius)); }
    
            Cylinder(double r, double len) : Circle(r), length(len) {}
    };
    

    And then, since Circle::calcVal() and Cylinder::calcVal() are both calculating the same PI * radius * radius value, where Cylinder is just multiplying the result by length, you can actually call Circle::calcVal() inside of Cylinder::calcVal() to do the common work, eg:

    double calcVal() override { return (length * Circle::calcVal());