nkint
nkint

Reputation: 11733

class inheritance call a different constructor

hei i have a c++03 class with a simple constructor that take an integer. And a derived class with serialization methods that should take a filename as a constructor, load the integer from it, and then call the first constructor.

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

and a derived class:

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

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

i tried some different solution but every time i get

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

Upvotes: 1

Views: 674

Answers (6)

Andrew Rasmussen
Andrew Rasmussen

Reputation: 15099

In C++ the Base class is constructed BEFORE the Child class, so you will not be able to do this. You could make a Factory that takes a filename and creates an object based on what is in that file.

Example:

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

And then call it like so:

XmltableA myObj = XmltableAFactory::build(filename);

There are a few things to note.

  1. This means that you will not need the string xmlfilename cosntructor in the XmltableA class because as discussed above, you cannot know foo before the base class's constructor is called.
  2. You can either choose to return from the factory by value or by pointer. The compiler might optimize the return by value because you are creating the object and returning it on the same line. However, return by pointer is usually known to be faster, but you'll have to create a new object and then make sure to delete it when you're done with it.
  3. If you don't want to muck about with memory, take a look at boost's auto_ptr and shared_ptr.

Upvotes: 3

justin
justin

Reputation: 104698

Initialize it, like so:

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

You may also consider:

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

public:
  XmlableA(string xmlfilename) : A(LoadXML(xmlfilename)) {
  }

Upvotes: 4

Useless
Useless

Reputation: 67723

OK, so the first one is easy:

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

The second one requires doing something like

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

which we can implement as

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

public:
    // ...

Note that fooFromXML, which loads the XML file and returns the integer you need, must be static, because when we call it we don't yet have an XmlableA instance to invoke it on.


For multiple arguments (and as a general design), the factory is probably best: if you're wedded to the constructor model and don't care about efficiency, you can do:

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

if you're concerned about parsing the XML file repeatedly, and don't care about re-entrancy, you can "memoize" xFromXML by having it cache state in a static member.

Upvotes: 2

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361322

Almost all answers are same, so I would suggest a different solution, which I would prefer personally.

Define a static member function Create as:

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

Usage:

XmlableA xmlable = XmlableA::Create(xmlFile);

Upvotes: 4

znkr
znkr

Reputation: 1756

If your class A does not have a default constructor you have to explicitly call a constructor in the initialization list of your derived class. XmlableA(string fn) : A(readIntegerFromFile(fn)) {}.

However, you should think about "outsourcing" the serialization into a separate class. E.g. what would happen if you have an object of type A and now you want to serialize it? You couldn't because you can only serialize a XmlableA. Furthermore, what would happen if your client decides that he no longer wants a XML serialization but Yaml or some proprietary format? You would have to change all your code.

Upvotes: 1

smparkes
smparkes

Reputation: 14063

If you want to do something before the call to A::A(int), you end up having to hack, something like

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

Upvotes: 2

Related Questions