Невозможно инициализировать параметр объекта типа 'Parent' с помощью выражения типа 'Derived' - PullRequest
0 голосов
/ 25 апреля 2019

Я реализую простую иерархию: система и устройство будут двумя базовыми классами. Система имеет устройства. Тогда у меня была бы сеть, полученная из системы, которая будет иметь компьютеры. Компьютер является производным от системы и устройства. И, наконец, компьютер имеет различные устройства, такие как процессор, память и т. Д. Причина, по которой компьютер является устройством, заключается в том, что сеть - это система, а устройства хранят системы. Компьютер - это система, потому что он хранит устройства (процессор, память и т. Д.)

В любом случае, моя реализация пока:

class Device {
public:
    explicit Device(unsigned property): property(property) {}
    friend void swap(Device &first, Device &second) {
        using std::swap;
        swap(first.property, second.property);
    }
    Device& operator=(Device other) {
        swap(*this, other);
        return *this;
    }
private:
    Device() = default;

    unsigned property;
};

class System {
public:
    explicit System(const string &name): name(name) {}
    friend void swap(System &first, System &second) {
        using std::swap;
        swap(first.name, second.name);
        swap(first.devices, second.devices);
    }
    System& operator=(System other) {
        swap(*this, other);
        return *this;
    }
protected:
    void addDevice(Device b1) {
        devices.push_back(b1);
    }
private:
    vector<Device> devices;
    string name;
};

class Computer: public System, public Device {
public:
    Computer(unsigned property, const string& name): System(name), Device(property) {}

    Computer& addAddress(const string &address) {
        addresses.emplace_back(address);
        return *this;
    }
    Computer& addComponent(Device newDevice) {
        System::addDevice(newDevice); //error
        return *this;
    }
private:
    vector<const string> addresses;
};

class Network: public System {
public:
    Network(const string& name): System(name) {}

    Network& addComputer(Device newComputer) {
        System::addDevice(newComputer); //no error
        return *this;
    }
};

class CPU: public Device {
public:
    CPU(unsigned coreCount, unsigned frequency): Device(coreCount), frequency(frequency) {}
private:
    unsigned frequency;
};

Компьютер addComponent () имеет ошибку, потому что cannot initialize object parameter of type System with an expression of type Computer. Я не совсем уверен, что это значит, так как эта функция вызывается из класса Computer, который является Device, следовательно, он должен иметь доступ к родительской addDevice (). Параметр функции имеет значение Device.

Также сбивает с толку тот факт, что мой класс Network, где функция addComputer () использует тот же набор инструкций, не имеет ошибки.

Может кто-нибудь объяснить, как мой дизайн имеет недостатки?

Ответы [ 2 ]

0 голосов
/ 24 мая 2019

Это сообщение об ошибке выскочило для меня сегодня, когда я находился в процессе кодирования производного класса, и в моем случае ключом было то, что производный класс был - в тот момент - неинстанцибельным. 1

Как только я добился достаточного прогресса в производном классе, чтобы его можно было создать, ошибки испарились.

Причина

Производный вызов, из которого вы печатаете, чтобы вызвать базовый класс, в настоящее время не может быть создан.

Демонстрация

Рассмотрим следующий код, который имеет два отношения наследования.

class Type {
public:
    Type(){}
    virtual ~Type() {}
    virtual void m() = 0;
};

class SubType: public Type {
public:
    SubType(): Type() {}
    virtual ~SubType() {}
    // virtual void m() override; // <== Important code commented out here
};
// void SubType::m() {}           // <== and here


class Base {
public:
    Base() {};
    virtual ~Base() {}
    virtual void m();
};

class Derived: public Base, public Type {
public:
    Derived(): Base() {}
    virtual ~Derived() override {}
    virtual void m() override;
protected:
    SubType m_troublesome;  // <== Note member here has incomplete type when
                            //     comments are in place
};

void Base::m() {}

void Derived::m() {
    Base::m();              // <== Tricky error message on this line
}

Попытка скомпилировать это с

$ clang --std=c++11 -Wall -pedantic -c test.cc

и вы получите отзыв

test.cc:34:13: error: field type 'SubType' is an abstract class
    SubType m_troublesome;
            ^
test.cc:8:18: note: unimplemented pure virtual method 'm' in 'SubType'
    virtual void m() = 0;
                 ^
test.cc:42:11: error: cannot initialize object parameter of type 'Base' with an
      expression of type 'Derived'
    Base::m();

Если вы видите все три вместе, вы знаете, с чего начать, но если вы используете clang в качестве линтера (как это делают многие IDE), то вы можете увидеть третий (который встречается в строке Base::m();, совершенно допустимый фрагмент кода) в контексте, отделенном от первых двух.

Мгновенное замешательство.

Если вы удалите комментарии из двух отмеченных разделов кода (сделав SubType завершенным и, таким образом, сделав возможным создание экземпляров Derived объектов), код скомпилируется чисто.

Два возможных урока здесь:

  • Завершите то, что вы начали. Если бы я не оставил аналог SubType наполовину готовым, ситуация никогда бы не возникла.
  • Если линтер сбивает с толку, посмотрите полный вывод ошибок сборки.

1 В частности, у меня был объявлен элемент с типом, в котором я еще не переопределил унаследованный абстрактный виртуальный метод.

0 голосов
/ 26 апреля 2019

Вы не можете иметь std::vector экземпляров базового класса и сохранять в нем производные экземпляры. Используйте указатели на базовый класс в векторе, например, std::vector<std::shared_ptr<Device>>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...