Reputation: 11733
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
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.
string xmlfilename
cosntructor in the XmltableA
class because as discussed above, you cannot know foo before the base class's constructor is called.new
object and then make sure to delete
it when you're done with it.auto_ptr
and shared_ptr
.Upvotes: 3
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
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
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
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
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