类继承调用不同的构造函数

时间:2012-02-23 18:17:32

标签: c++ inheritance constructor

hei我有一个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 个答案:

答案 0 :(得分:4)

初始化它,如下:

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)) {
  }

答案 1 :(得分:4)

几乎所有的答案都是一样的,所以我建议采用不同的解决方案,我个人更愿意。

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);

答案 2 :(得分:3)

在C ++中,Base类是在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类中的XmltableA cosntructor,因为如上所述,在调用基类的构造函数之前,您无法知道foo。
  2. 您可以选择通过值或指针从工厂返回。编译器可能会按值优化返回值,因为您正在创建对象并将其返回到同一行。但是,通常已知指针返回更快,但您必须创建一个new对象,然后确保在完成后delete
  3. 如果您不想记忆,请查看提升的auto_ptrshared_ptr

答案 3 :(得分:2)

如果你想在致电A::A(int)之前做某事,你最终不得不进行攻击,比如

int XmlableA::f(string filename) { /* load foo from xml */; return foo; }
XmlableA(string xmlfilename) : A(f(filename)) {}

答案 4 :(得分:2)

好的,所以第一个很容易:

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

第二个需要做类似

的事情
XmlableA(string xmlfilename) : A(fooFromXML(xmlfilename))
{
}

我们可以实现

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

public:
    // ...

请注意fooFromXML加载XML文件并返回所需的整数,必须是静态的,因为当我们调用它时,我们还没有{{1}实例调用它。


对于多个参数(以及作为一般设计),工厂可能是最好的:如果您已经与构造函数模型结合并且不关心效率,那么您可以这样做:

XmlableA

如果您担心重复解析XML文件而不关心重新入侵,可以通过将其缓存状态置于静态成员中来“memoize”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)) { }

答案 5 :(得分:1)

如果您的A类没有默认构造函数,则必须在派生类的初始化列表中显式调用构造函数。 XmlableA(string fn) : A(readIntegerFromFile(fn)) {}

但是,您应该考虑将序列化“外包”到一个单独的类中。例如。如果你有一个A类型的对象,现在想要序列化它会发生什么?你不能,因为你只能序列化XmlableA。此外,如果您的客户决定他不再需要XML序列化但是Yaml或某些专有格式,会发生什么?您必须更改所有代码。