наследование классов вызвать другой конструктор - PullRequest
1 голос
/ 23 февраля 2012

Привет, у меня есть класс C ++ 03 с простым конструктором, который принимает целое число. И производный класс с методами сериализации, которые должны принимать имя файла в качестве конструктора, загружать из него целое число и затем вызывать первый конструктор.

class A {
public:
    A(int foo);
}

и производный класс:

class XmlableA : public A {
public:
    XmlableA(int foo);

    XmlableA(string xmlfilename) {
        //load foo from xml
        // call A::A(foo)
    }
}

Я попробовал какое-то другое решение, но каждый раз, когда получаю

no matching function for call to ‘A::A()’

Ответы [ 6 ]

4 голосов
/ 23 февраля 2012

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

Определите static функцию-члена Create как:

class XmlableA : public A {
public:
    XmlableA(int foo);

    //static member function
    static XmlableA Create(string const & xmlfilename) 
    {
        //load foo from xml
         int foo = /*load from file*/;
         return XmlableA(foo);
    }
};

Использование:

XmlableA xmlable = XmlableA::Create(xmlFile);
4 голосов
/ 23 февраля 2012

Инициализируйте это так:

XmlableA(int foo) : A(foo) {}

Вы также можете рассмотреть:

private:
  static int LoadXML(const string& xmlfilename) {
    int ret = ...; << load here
    return ret;
  }

public:
  XmlableA(string xmlfilename) : A(LoadXML(xmlfilename)) {
  }
3 голосов
/ 23 февраля 2012

В C ++ базовый класс создается ДО класса Child, поэтому вы не сможете этого сделать.Вы можете создать Factory , который принимает имя файла и создает объект на основе того, что находится в этом файле.

Пример:

class XmltableAFactory {
public:
    static XmltableAFactory build(string xmlfilename) {
        // read int foo from xmlfilename
        return XmltableAFactory(foo);
    }
};

И затем вызываете его так:

XmltableA myObj = XmltableAFactory::build(filename);

Следует отметить несколько вещей:

  1. Это означает, что вам не понадобится string xmlfilename cosntructor в классе XmltableA, потому что, как обсуждалось выше,вы не можете знать foo до вызова конструктора базового класса.
  2. Вы можете выбрать возврат из фабрики по значению или по указателю.Компилятор может оптимизировать возврат по значению, потому что вы создаете объект и возвращаете его в той же строке.Однако возврат по указателю обычно считается более быстрым, но вам нужно будет создать объект new, а затем убедиться, что он будет delete, когда вы закончите с ним.
  3. Если вы этого не сделаетене хочу возиться с памятью, взгляните на Boost auto_ptr и shared_ptr.
2 голосов
/ 23 февраля 2012

ОК, поэтому первое легко:

XmlableA::XmlableA(int foo) : A(foo)
{
}

Второе требует выполнения чего-то вроде

XmlableA(string xmlfilename) : A(fooFromXML(xmlfilename))
{
}

, которое мы можем реализовать как

class XmlableA : public A
{
    static int fooFromXML(string filename);

public:
    // ...

Обратите внимание, что fooFromXML, который загружает файл XML и возвращает нужное вам целое число, должен быть статическим, потому что когда мы его вызываем, у нас еще нет экземпляра XmlableA для его вызова.


Для нескольких аргументов (и в качестве общего дизайна), фабрика, вероятно, лучше всего: если вы привязаны к модели конструктора и не заботитесь об эффективности, вы можете сделать:

class XmlableA : public A
{
    static int intFromXML(char const *varname, string const &filename);

public:
    XmlableA(string const &xmlfilename)
    : A(intFromXML("foo", xmlfilename), intFromXML("bar", xmlfilename))
    {
    }

Если вы беспокоитесь о повторном анализе XML-файла и не заботитесь о повторном входе, вы можете «запомнить» xFromXML, поместив его в состояние кэширования в статическом члене.

2 голосов
/ 23 февраля 2012

Если вы хотите что-то сделать перед вызовом A::A(int), вам придется взломать что-то вроде

int XmlableA::f(string filename) { /* load foo from xml */; return foo; }
XmlableA(string xmlfilename) : A(f(filename)) {}
1 голос
/ 23 февраля 2012

Если в вашем классе A нет конструктора по умолчанию, вы должны явно вызвать конструктор в списке инициализации вашего производного класса.XmlableA(string fn) : A(readIntegerFromFile(fn)) {}.

Однако вы должны подумать об «аутсорсинге» сериализации в отдельный класс.Например, что произойдет, если у вас есть объект типа A, и теперь вы хотите его сериализовать?Вы не могли, потому что вы можете только сериализовать XmlableA.Кроме того, что произойдет, если ваш клиент решит, что ему больше не нужна сериализация XML, а есть Yaml или какой-то проприетарный формат?Вы должны изменить весь свой код.

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