Предотвращение неявного вызова базового конструктора в конструкторе копирования - PullRequest
0 голосов
/ 16 октября 2018

Я хочу предотвратить вызов конструктора по умолчанию, чтобы я мог заставить пользователя использовать специализированный конструктор.Для этого я просто удаляю конструктор по умолчанию.

Возникает проблема, когда я хочу создать конструктор копирования для производного класса.Кажется, что конструктор копирования производного класса делает неявный вызов родительского конструктора по умолчанию (который удаляется).Компилятору это не нравится!

Есть ли способ обойти этот неявный вызов?

#include <iostream>

class Base
{
public:
    Base() = delete;

    Base(int x)
    : _x(x)
    {
        std::cout << "Base's constructor" << std::endl;
    }

    Base(const Base &other)
    {
        std::cout << "Base's copy constructor" << std::endl;
        this->_x = other._x;
    }

protected:
    int _x;
};

class Derived : public Base
{
public:
    Derived() = delete;

    Derived(int x, int y)
    : Base(x),  _y(y)
    {
        std::cout << "Derived's constructor" << std::endl;
    }

    Derived(const Derived &other)
    {
        // Implict call to Base(), which is deleted, and compilation fails.
        std::cout << "Derived's copy constructor" << std::endl;
        this->_x = other._x;
        this->_y = other._y;
    }

protected:
    int _y;
};

int main(int argc, char** argv)
{
    Derived d(10,10);
    Derived d2(d);
}

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Вам не нужно использовать =delete для предотвращения вызова конструктора по умолчанию.Вы можете использовать предыдущую технику, которая должна была объявить это private.Конечно, в этом случае, поскольку вы хотите, чтобы он был доступен для производных классов, вы должны сделать его protected.

Но вы также можете явно создать необходимый базовый класс:

Derived(const Derived &other)
    : Base(other._x)
    , _y(other._y)
{
    std::cout << "Derived's copy constructor" << std::endl;
}
0 голосов
/ 16 октября 2018

Ваша проблема в том, что, поскольку все конструкторы инициализируют все свои элементы перед вводом тела конструктора,

Derived(const Derived &other)
{
    // Implict call to Base(), which is deleted, and compilation fails.
    std::cout << "Derived's copy constructor" << std::endl;
    this->_x = other._x;
    this->_y = other._y;
}

фактически

Derived(const Derived &other) : Base(), _y()
{
    // Implict call to Base(), which is deleted, and compilation fails.
    std::cout << "Derived's copy constructor" << std::endl;
    this->_x = other._x;
    this->_y = other._y;
}

Где Base() вызывает базуКонструктор класса по умолчанию.

Вам нужно использовать список инициализаторов членов для вызова конструктора копирования базового класса вместо конструктора по умолчанию.Для этого вы используете

Derived(const Derived &other) : Base(other), _y(other._y)
{
    // Implict call to Base(), which is deleted, and compilation fails.
    std::cout << "Derived's copy constructor" << std::endl;
    // this->_x = other._x; no longer needed as Base(other) takes care of _x
    // this->_y = other._y; no longer needed as _y(other._y) takes care of _y
}

Вы также должны обновить конструктор копирования Base до

Base(const Base &other) : _x(other._x)
{
    std::cout << "Base's copy constructor" << std::endl;
}

Также обратите внимание, что вы можете получитьбез определения любого из этих конструкторов копирования.Поскольку вы не определили деструктор, компилятор автоматически сгенерирует конструкторы копирования для обоих классов, и эти конструкторы копирования по умолчанию будут работать.

...