1

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()’

6 Answers 6

4

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);
Sign up to request clarification or add additional context in comments.

2 Comments

This is good if you don't need to derive from XmlableA ... which only just serves to demonstrate that if the only reason for XmlableA is to provide an additional constructor it's not a great use of derivation.
yeah this seems the better solution till now. but also the advice from @krynr of ousourcing serialization is an elegant idea! (and it could be adapted easily putting in ax external class the static memeber Create!)
4

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

11 Comments

@nkint 4 parameters to A(...) or to XmlableA(...)?
I think LoadXML should be a private static member function if it is not needed by any other class, or function.
@Nawaz: heck, put it in namespace {} then it doen't even need to be in XmlableA.
@nkint I don't think there's any solution except some variant of Nawaz's then.
@Nawaz good point on visibility (+1), for production code. perhaps a bit pedantic for a quick SO answer. nevertheless - updated, thanks.
|
3

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.

Comments

2

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

4 Comments

So pass xmlfilename to f().
@FredLarson; Oops. Right. Fixed.
that method f needs to be static if you're calling it before you have an instance
@Useless doesn't have to be though it's safest if it is. If it's not, you have to be pretty careful about what you do in it.
2

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.

2 Comments

good solution! int foo was only an example, i have 4 parameters actually
you mean, A::A() takes more than one argument, and you need to unpack them all from the XML file?
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.