简体   繁体   中英

C++ Grand Parent default constructor call

I have the following code that runs just fine as long as I have the Rect default constructor included. However if I comment it out hope that it will just 'skip' to the Shape default constructor it fails to compile.

#include <cstdio>

class Shape
{
public:
    Shape()
    {
        printf("Shape default called\n");
    }
};

class Rect : public Shape
{
public:
    int width;
    int height;

    Rect()
    {
        printf("Rect default called\n");
    }

    Rect(int width, int height)
    {
        this->width = width;
        this->height = height;
    }

    int area()
    {
        return width*height; 
    }
};

class Square : public Rect
{
public:
    Square(int width)
    {   
        printf("Square constructor called.\n");
        this->width = width;
        this->height = width;
    }
};

int main(int argv, char** argc)
{
    printf("...\n");
    Square r = Square(10);
    printf("Area: %d\n", r.area());
    return 0;
}

When the program runs and compiles I get the following output

...

Shape default called

Rect default called

Square constructor called.

Area: 100

I was hoping to simply remove the Rect default constructor and get

...

Shape default called

Square constructor called.

Area: 100

because all the rect default constructor will do is sit there to satisfy clang's error. It isn't intended to do anything extra. Is there a way to accomplish this?

You should use member initializer list syntax to call appropriate Rect constructor with your arguments:

Square(int width) : Rect(width, width)
{
    printf("Square constructor called.\n");
}

Notice that you don't need to manually assign to this->width and this->height , Rect constructor will do this for you.

Main advantage of using initializer list instead of assignment in constructor body, is that it allows to avoid unnecessary calls to default constructor. See this answer for detailed explanation.

It also allows you to inherit from (and have data members of) classes that don't have default constructor.

If you need to do something with the values first, it's perfectly ok to assign values in constructor body, but your base class (or member class, if you are initializing a data member) must have a default constructor.

The reason for this is that every data member's constructor must be (and is) called BEFORE your class' constructor body starts to execute. Initializer list allows you to choose which constructor gets called, depending on arguments you provide. If you don't initialize a data member in initializer list, it will be constructed using its default constructor (that is why it must be declared) before it can be assigned any value in constructor body.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM