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

C++ 类继承调用不同的构造函数,c++,inheritance,constructor,C++,Inheritance,Constructor,我有一个c++03类,它有一个简单的构造函数,它接受一个整数。以及具有序列化方法的派生类,这些方法应将文件名作为构造函数,从中加载整数,然后调用第一个构造函数 class A { public: A(int foo); } 和派生类: class XmlableA : public A { public: XmlableA(int foo); XmlableA(string xmlfilename) { //load foo from xml

我有一个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()’

如果您想在调用A::Aint之前做一些事情,那么您最终必须进行黑客攻击,比如

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

如果您想在调用A::Aint之前做一些事情,那么您最终必须进行黑客攻击,比如

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

<>在C++中,基类是在子类之前构建的,所以您将不能这样做。您可以创建一个文件名,并根据该文件中的内容创建一个对象

例如:

class XmltableAFactory {
public:
    static XmltableAFactory build(string xmlfilename) {
        // read int foo from xmlfilename
        return XmltableAFactory(foo);
    }
};
然后这样称呼它:

XmltableA myObj = XmltableAFactory::build(filename);
有几件事需要注意

这意味着您将不需要XmltableA类中的字符串xmlfilename协构造函数,因为如上所述,在调用基类的构造函数之前,您无法知道foo。 您可以选择通过值或指针从工厂返回。编译器可能会优化按值返回,因为您正在创建对象并在同一行上返回它。然而,指针返回通常会更快,但您必须创建一个新对象,然后确保在完成后将其删除。 如果你不想浪费内存,可以看看boost的auto_ptr和shared_ptr。
<>在C++中,基类是在子类之前构建的,所以您将不能这样做。您可以创建一个文件名,并根据该文件中的内容创建一个对象

例如:

class XmltableAFactory {
public:
    static XmltableAFactory build(string xmlfilename) {
        // read int foo from xmlfilename
        return XmltableAFactory(foo);
    }
};
然后这样称呼它:

XmltableA myObj = XmltableAFactory::build(filename);
有几件事需要注意

这意味着您将不需要XmltableA类中的字符串xmlfilename协构造函数,因为如上所述,在调用基类的构造函数之前,您无法知道foo。 您可以选择通过值或指针从工厂返回。编译器可能会优化按值返回,因为您正在创建对象并在同一行上返回它。然而,指针返回通常会更快,但您必须创建一个新对象,然后确保在完成后将其删除。 如果你不想浪费内存,可以看看boost的auto_ptr和shared_ptr。
初始化它,如下所示:

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

初始化它,如下所示:

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

好的,第一个很简单:

XmlableA::XmlableA(int foo) : A(foo)
{
}
第二个需要做一些类似的事情

XmlableA(string xmlfilename) : A(fooFromXML(xmlfilename))
{
}
我们可以将其作为

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

public:
    // ...
请注意,加载XML文件并返回所需整数的fooFromXML必须是静态的,因为当我们调用它时,我们还没有一个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缓存状态保存在静态成员中来记忆xFromXML。

好的,因此第一个很简单:

XmlableA::XmlableA(int foo) : A(foo)
{
}
第二个需要做一些类似的事情

XmlableA(string xmlfilename) : A(fooFromXML(xmlfilename))
{
}
我们可以将其作为

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

public:
    // ...
请注意,加载XML文件并返回所需整数的fooFromXML必须是静态的,因为当我们调用它时,我们还没有一个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缓存状态保存在静态成员中来记忆xFromXML。

如果类a没有默认构造函数,则必须在派生类的初始化列表中显式调用构造函数。XmlableAstring fn:AreadIntegerFromFilefn{}


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

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

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

几乎所有答案都是相同的,因此我建议使用不同的解决方案,我个人更喜欢这种解决方案

将静态成员函数定义为创建:

用法:

XmlableA xmlable = XmlableA::Create(xmlFile);

几乎所有的答案都是一样的,所以我会建议一个不同的解决方案,我个人更喜欢

将静态成员函数定义为创建:

用法:

XmlableA xmlable = XmlableA::Create(xmlFile);

因此,将xmlfilename传递给f.@FredLarson;哎呀。正当修正了。如果您在创建一个instance@Useless不一定非要这样,即使这样做最安全。如果不是,您必须非常小心在其中执行的操作;哎呀。正当修正了。如果您在创建一个instance@Useless不一定非要这样,即使这样做最安全。如果不是,你必须非常小心你在里面做什么。很好的解决方案!int foo只是一个例子,我有4个参数,实际上你的意思是,A::A接受多个参数,你需要从XML文件中解包它们?很好的解决方案!int foo只是一个例子,我有4个参数,实际上你的意思是,A::A接受多个参数,你需要将它们从XML文件中解压出来?@nkint 4参数到。。。或者对于XmlableA…?我认为LoadXML应该是一个私有的静态成员函数,如果其他任何类或函数都不需要它。@Nawaz:heck,把它放在命名空间{}中,那么它甚至不需要在XmlableA中。@nkint我认为除了Nawaz的一些变体之外,没有任何解决方案。@Nawaz对于生产代码来说,可见性+1是一个很好的观点。对于一个如此快速的回答,也许有点迂腐。不过-更新了,谢谢。@nkint 4参数到。。。或者对于XmlableA…?我认为LoadXML应该是一个私有的静态成员函数,如果其他任何类或函数都不需要它。@Nawaz:heck,把它放在命名空间{}中,那么它甚至不需要在XmlableA中。@nkint我认为除了Nawaz的一些变体之外,没有任何解决方案。@Nawaz对于生产代码来说,可见性+1是一个很好的观点。对于一个如此快速的回答,也许有点迂腐。不过-更新了,谢谢。如果您不需要从XmlableA派生,这是很好的。。。这只是为了证明,如果XmlableA的唯一原因是提供一个额外的构造函数,那么派生就没有什么用处。是的,到目前为止,这似乎是更好的解决方案。但是,来自@krynr的关于取消资源序列化的建议也是一个很好的主意!而且,它可以很容易地进行调整,放入静态memeber创建的ax外部类中!如果您不需要从XmlableA派生,这是很好的。。。这只是为了证明,如果XmlableA的唯一原因是提供一个额外的构造函数,那么派生就没有什么用处。是的,到目前为止,这似乎是更好的解决方案。但是,来自@krynr的关于取消资源序列化的建议也是一个很好的主意!而且,它可以很容易地进行调整,放入静态memeber创建的ax外部类中!