Reputation: 2304
I'm trying to create a way to handle many different versions of a protocol, similar to the question How to handle different protocol versions transparently in c++?. I agree that a chain of inheritance would solve the problem well.
This is how I would do it in Java: create an IParser
interface, and have several ParserV0
, ParserV1
, ... classes, inheriting from each other and implementing IParser
.
I understand that creating that structure is possible in C++ due to some multiple inheritance and virtual
tricks. Here's the catch: in Java, if I wanted a parser, I think, I would be able to say IParser parser = getCorrectVersion(...)
. I would get some version of ParserV0
, etc., implementing IParser
and call the methods I need.
What's the equivalent to that last step in C++? There doesn't seem to be a way for me to ask for any class implementing another and then being able to call its methods.
EDIT:
Here's my attempt at doing what jtedit has suggested, since I have seen similar suggestions around StackOverflow:
class IParser {
public:
virtual const string doSomething(params) = 0;
};
class ParserPreVersion : public IParser {
public:
const string doSomething(params) {
// do some thing
}
};
class ParserFactory {
...
public:
const IParser* generateParser() {
return new ParserPreVersion();
}
};
In another part of my code, I say
const IParser parser = *(ParserFactory().generateParser());
I've been getting compile-time errors with this code and variations of it, though, leading me to ask this question.
In member function 'const IParser* generateParser()':
error: cannot allocate an object of abstract type 'ParserPreVersion'
note: because the following virtual functions are pure within 'ParserPreVersion':
note: virtual const std::string IParser::doSomething(params)
also
error: cannot declare variable 'parser' to be of abstract type 'const IParser'
note: since type 'const IParser' has pure virtual functions
I don't understand exactly why I have the first one, but the second is somewhat expected, and was the main concern in my question.
EDIT 2
And my attempt at what Scis has suggested (code declaring classes and functions is the same)
unique_ptr<IParser> getParser() {
return unique_ptr<IParser>(new ParserV0());
}
auto parser(getParser());
This time, I get a vtable
lookup error, since it seems be looking for the function definition in IParser
.
FINAL EDIT:
I realized my code was a little messy and I was missing some modifiers for parameters, so that the virtual one and the overriding one didn't match up. The errors make a lot of sense. Thank you for your help!
Upvotes: 4
Views: 1987
Reputation: 5467
You need an Abstract Factory, or a parametrized Factory Method; which is sorta what jtedit is describing. Usually in doing this you make the constructor themselves protected and only expose a factory method.. Check out the Gang of Four Creational Patterns for more information
http://en.wikipedia.org/wiki/Design_Patterns
Upvotes: 1
Reputation: 2984
You could use an abstract base class and create the required function as virtual
as noted before the only thing I'd suggest is using unique_ptr
and not raw pointers this way you'll not have to delete
the memory yourself when you are finished using it (similarly to what you'd have in Java):
Here a sample:
unique_ptr<IParse> getParser(int x){
switch (x){
case 1:
return unique_ptr<IParse>(new P1());
break;
case 2:
return unique_ptr<IParse>(new P2());
break;
}
return nullptr;
}
int main() {
auto p1(getParser(1));
p1->foo();
auto p2(getParser(2));
p2->foo();
return 0;
}
where foo
is declared as : virtual void foo() = 0;
. See full example here.
Upvotes: 3
Reputation: 1470
Your getCorrectVersion() function needs to return a pointer to the interface, ie, the IParser
eg:
IParser* getCorrectVersion(int version){
switch(version){
case 0:
return new ParserV0();
case 1:
return new ParserV1();
}
}
To be able to call the methods, the methods you want must be virtual in IParser
eg:
class IParser{
public:
virtual int getInt() = 0;
};
Upvotes: 3