Наследование, конструкторы копирования и неявное приведение типов - PullRequest
0 голосов
/ 13 декабря 2018

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

Я уверен, что это должно быть возможно в C ++.Вот пример:

#include <string>


class Base
{

public:

    friend
    void swap(Base& l, Base& r)
    {
        using std::swap;

        swap(l.a, r.a);
    }

    Base()
        : a{1}
    {
    }

    Base(const int a)
        : a{a}
    {
    }

    virtual
    ~Base()
    {
    }

    Base(const Base& base)
        : a{base.a}
    {
    }

    Base(Base&& base)
        : Base()
    {
        swap(*this, base);
    }

    Base& operator=(Base base)
    {
        swap(*this, base);

        return *this;
    }

protected:

    int a;

};


class Derived : public Base
{


protected:

    std::string b;

};

int main()
{

    Base base(2);
    Derived derived(base);

}

Ошибка (g++ main.cpp):

main.cpp: In function ‘int main()’:
main.cpp:71:31: error: no matching function for call to ‘Derived::Derived(Base&)’
     class Derived derived(base);
                               ^
main.cpp:57:7: note: candidate: Derived::Derived()
 class Derived : public Base
       ^~~~~~~
main.cpp:57:7: note:   candidate expects 0 arguments, 1 provided
main.cpp:57:7: note: candidate: Derived::Derived(const Derived&)
main.cpp:57:7: note:   no known conversion for argument 1 from ‘Base’ to ‘const Derived&’
main.cpp:57:7: note: candidate: Derived::Derived(Derived&&)
main.cpp:57:7: note:   no known conversion for argument 1 from ‘Base’ to ‘Derived&&’

Таким образом, компилятор не знает, как преобразовать экземпляр Base вDerived неявно.

Я думал, что это должно быть законно в C ++.Требуется ли явное выражение преобразования?

Ответы [ 5 ]

0 голосов
/ 13 декабря 2018

Я нашел то, что искал (я не мог вспомнить название, поэтому не мог найти его раньше).Однако этот метод на самом деле не работает из-за того, что я использую наследование.(Или, по крайней мере, я не знаю, как заставить это работать.)

Оператор преобразования типов:

Base::operator Derived()
{
    Derived derived;
    derived.a = a;
    return derived;
}

Это на самом деле не компилируется, потому что компилятор не знает, что Derived есть.(Поскольку Derived наследуется от Base.) Я не знаю, возможно ли выполнить эту работу, разделив блоки компиляции.

0 голосов
/ 13 декабря 2018

То, что вы делаете, само по себе не имеет особого смысла, потому что Base не является подтипом Derived, поэтому его нельзя использовать в качестве замены / замены, однако вы можете попытаться придать ему смысл(так же, как при инициализации из любого другого типа), написав конструктор преобразования:

class Derived : public Base
{
public:
Derived(const Base &bs) : Base(bs), b("constructed from base") {}

protected:

    std::string b;

};

Это сначала инициализирует Derived Base часть из bs, а затем инициализирует строку b с некоторымизначение (хотя вы можете не указывать его, если хотите, чтобы оно было по умолчанию вставлено в пустую строку).

https://godbolt.org/z/GMELW_

0 голосов
/ 13 декабря 2018

Существует простой способ решения этой проблемы: потянув конструктор Base в область действия Derived.

Это можно сделать с помощью оператора using:

class Derived : public Base
{
public:
    using Base::Base;  // Pulls in the Base class constructors into the scope of Derived

    ...
};
0 голосов
/ 13 декабря 2018

это утверждение Derived derived(base); или для упрощения B b(A()); выполните неявное преобразование типа A в тип B, что допустимо только в том случае, если class B прямо или косвенно наследуется от Class A.

Почему?Поскольку class B может содержать новую информацию, в вашем случае string b, а приведение не "добавляет" информацию.

0 голосов
/ 13 декабря 2018

Да, вам нужно явно разыграть от Base до Derived.Каждый Mercedes - это автомобиль, но не каждый автомобиль - это Mercedes.

...