C ++ инициализировать объект в конструкторе (полиморфный) - PullRequest
0 голосов
/ 20 сентября 2019

В настоящее время я пытаюсь достичь чего-то в C ++, что я делаю в Java все время: допустим, у меня есть функция bool init() в качестве члена моего класса A, которая вызывается в конструкторе A иесли он вернет false, конструктор выдаст исключение.

Теперь я создаю новый класс B, который наследуется от A, но ему нужно выполнить другую инициализацию, чтобы он возвратил trueв других случаях, отличных от оригинального A::init().

. В Java я бы просто переписал метод в B, и когда конструктор A вызывается в процессе построения B, он вызовет B::init() из конструктора А. и все работает как чемпион.

В C ++, однако, я только что узнал, что не могу вызывать виртуальные функции в конструкторе (то есть я могу, но это не так)вести себя так же).Мой вопрос сейчас заключается в том, как я могу обрабатывать такие инициализации / проверки, которые вызываются из конструктора, но это может потребоваться изменить в производной класса.
Конечно, можно было бы не вызывать это в конструкторе, нопредоставьте программисту возможность явно вызывать функцию init() после создания объекта, но мне это не нравится, поскольку об этом можно забыть, что приведет к странному состоянию объекта.


Небольшой пример:
Учтите, что A и B читают содержимое жестко закодированного файла.A читает fileA.txt и B читает fileB.txt.Я хочу, чтобы конструкция объекта прошла успешно только при наличии соответствующего файла.Таким образом, проверка должна происходить в конструкторе объекта.Если запись проверки в конструктор напрямую приведет к сбою B всегда (при условии, что оба файла не могут существовать одновременно), поэтому я всегда выбирал функцию, которая выполняет проверку и которую можно перезаписать.Что такое C ++ способ сделать это?

Ответы [ 2 ]

2 голосов
/ 21 сентября 2019

Принимая во внимание, что вызов производного класса для собственной функции инициализации кажется более подходящим, в качестве альтернативы вы можете создать фабричную функцию, которая вызывает ваш метод virtual init:

class A
{
public:
    virtual ~A() = default;
    virtual bool init() = 0;

public:
    template <typename T, typename ... Ts>
    static T Create(Ts&&...args)
    {
        static_assert(std::is_base_of<A, T>::value);
        T derived(std::forward<Ts>(args)...);
        if (!derived.init()) {
            throw std::runtime_error("...");
        }
        return derived;
    }
protected:
    A() = default;
};

class B : public A
{
    friend class A; // For factory
protected:
    B(/*..*/);
public:
    bool init() override;
};
1 голос
/ 21 сентября 2019

Для вашего примера вы должны написать абстрактный базовый класс, от которого наследуются A & B, с помощью чисто виртуальной статической константной функции, которая указывает, какой файл читается.Абстрактные классы в C ++ являются более мощными, чем интерфейсы в Java, и, следовательно, могут быть более полезными для решения подобных проблем, чем интерфейс Java.

Реальное решение этой проблемы - более глубокая проблема, которая до сих поря в течение часа пялился на спецификацию C ++, пытаясь понять.Я дам обновление, когда выясню, что конкретно говорит спецификация и как, если возможно, сделать это.Этот действительно получил меня.

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