I have an object presented as a reference/pointer to an interface. I would like to call a method on the concrete object if that method is present, without changing the interface, breaking encapsulation, or writing any horrible hacks. How can it be done?
Here's an example.
I have an interface:
class IChatty
{
public:
virtual ~IChatty() {};
virtual std::string Speak() const = 0;
};
And multiple concrete implementation of this interface:
class SimpleChatty : public IChatty
{
public:
~SimpleChatty() {};
virtual std::string Speak() const override
{
return "hello";
}
};
class SuperChatty : public IChatty
{
public:
void AddToDictionary(const std::string& word)
{
words_.insert(word);
}
virtual std::string Speak() const override
{
std::string ret;
for(auto w = words_.begin(); w != words_.end(); ++w )
{
ret += *w;
ret += " ";
}
return ret;
}
private:
std::set<std::string> words_;
};
The SuperChatty::AddToDictionary method is not present in the abstract IChatty interface, although it could be included in another, new interface.
In the real world, these objects are constructed through factories, themselves concrete instantiations of an abstract interface. However for our purposes that's orthogonal to the problem at hand:
int main()
{
IChatty* chatty = new SuperChatty;
chatty->AddToDictionary("foo");
std::cout << chatty->Speak() << std::endl;
}
Since AddToDictionary isn't part of the IChatty interface (and can't be part of it), I can's call it.
How can I call AddToDictionary on the chatty pointer without breaking encapsulation, writing some horrible hack, or taking any other design shortcuts?
NOTE: In the real world, the dictionary is part of the SuperChatty object itself, and cannot be separate from it.
NOTE2: I do not want to downcast to the concrete type.
Have dictionary be an object which can be updated and referenced by SuperChatty:
class Dictionary {
public:
void add(const std::string& word);
const std::set<std::string>>& words() const;
//..
};
class SuperChatty : public IChatty
{
public:
SuperChatty(Dictionary& dictionary) :
dictionary(dictionary) {
}
virtual std::string Speak() const override
{
auto words = dictionary.words();
ostringstream oss;
copy(words.begin(), words.end(),
ostream_iterator<string>(oss, " "));
return oss.str();
}
};
Usage:
int main()
{
Dictionary dictionary;
IChatty* chatty = new SuperChatty(dictionary);
dictionary.add("foo");
std::cout << chatty->Speak() << std::endl;
}
edit
Okay, the question changed.
If you're doing this properly, you need to isolate yourself from the bad underlying system:
struct Dictionary {
virtual ~Dictionary () {}
virtual void add(const std::string& word) = 0;
};
struct Instrumenter {
virtual ~Instrumenter () {}
virtual void addDictionary(Dictionary& dictionary) = 0;
};
struct Chatter {
virtual ~Chatter() {}
virtual string speak() const = 0;
virtual void instrument(Instrumenter& instrumenter) = 0;
};
These are implemented as:
class BasicChatter : public Chatter {
virtual string speak() const {
return chatty.Speak();
}
virtual void instrument(Instrumenter& instrumenter) {
// do nothing
}
private:
SimpleChatty chatty;
};
class SuperChatter : public Chatter {
SuperChatter () : dictionary(chatty);
virtual void instrument(Instrumenter& instrumenter) {
instrumenter.addDictionary(dictionary);
}
virtual string speak() const {
return chatty.Speak();
}
private:
SuperChatty chatty;
DictionaryImpl dictionary;
};
Make it derive from another interface and simply check, whether you can cast the object to that interface or not.
class IDictionary
{
public:
virtual ~IDictionary() {};
virtual void AddToDictionary(const std::string& word) = 0;
};
class SuperChatty : public IChatty, public IDictionary
{
... as before ...
};
int main()
{
IChatty* chatty = new SuperChatty;
IDictionary *dict = dynamic_cast<IDictionary*>(chatty);
if (dict) dict->AddToDictionary("foo");
std::cout << chatty->Speak() << std::endl;
}
The main problem is that you're trowing away information that you need.
So the main solution is to not throw away information, but there's not enough code presented to flesh out the details of that.
Secondly, a tehcnical kludge solution is to just downcast, using dynamic_cast:
IChatty* newThingy();
int main()
{
IChatty* chatty = newThingy();
if( SuperChatty* p_super_chatty = dynamic_cast<SuperChatty*>( chatty ) )
{
p_super_chatty->AddToDictionary("foo");
}
std::cout << chatty->Speak() << std::endl;
}
You can downcast safely because the know static type IChatty is polymorphic.
For this particular example, there's no reason to not create the object as this:
SuperChatty* chatty = new SuperChatty;
chatty->AddToDictionary("foo");
You can still pass chatty in the above segment as IChatty pointer or reference, e.g.
void Talk(IChatty *ch)
{
ch->Speak();
}
[Likewise for storing the chatty in a vector<IChatty*> or something like that].
My point here is that if you are going to use the "new" interface functions, then you probably also want to create the class that has the new interface.
Adding code to "try to cast it", etc, gets very messy very quickly, and is error prone.
Related
I want to make an abstract class, A that will be subclassed by Class B and Class C such that they will all use the same methods in the defined abstract class (B and C are A-able classes).
I have another class, Z, that will contain an array of A-able classes. I would like for it to have a function that allows it to swap between B and C in that array (ie. calling initializer/member function with an argument).
The below example, while not being exactly like what I'm describing above (not using abstract classes), showcases the same issue I'm running into: I'm unable to set the array to the correct subclass, since it's complaining that it was initialized as the parent class.
However, this should be possible to do right? What am I missing here?
#include <iostream>
#include <array>
class BaseItem {
protected:
std::string name;
BaseItem(const std::string & name) : name(name) {};
virtual void printName();
virtual ~BaseItem() = default;
};
class Item1: public BaseItem {
public:
using BaseItem::name;
Item1() : BaseItem("Book1") {}
void printName() {
std::cout << "1" << name;
}
};
class Item2: public BaseItem {
public:
using BaseItem::name;
Item2() : BaseItem("Book2") {}
void printName() {
std::cout << "2" << name;
}
};
class Library {
public:
std::array<BaseItem, 2> books;
void setToItem2() {
for (size_t i = 0; i < books.size(); i++) {
books[i] = new Item2();
}
}
void setToItem1() {
for (size_t i = 0; i < books.size(); i++) {
books[i] = new Item1();
}
}
void printBooks() {
for (auto& entry: books) {
entry->printName();
}
}
};
int main() {
Library a;
a.setToItem1();
a.printBooks();
a.setToItem2();
a.printBooks();
return 0;
}
Edit: Cleaned up a bit, also adding error message below:
prog.cpp: In member function ‘void Library::setToItem2()’:
prog.cpp:36:31: error: no match for ‘operator=’ (operand types are ‘std::array<BaseItem, 2>::value_type’ {aka ‘BaseItem’} and ‘Item2*’)
Edit2: Made the example code more representative of what I want to implement, utilizing code help from some of the existing answers.
Current potential solutions:
Evict books and pass in the correct subclass. This is currently what I'm going with. Just don't know if there is anything that can make this look cleaner (ie. all the casting looks a bit messy).
Make books a variant. The code looks cleaner here, but if I'm to extend to Item3, Item4, etc. I'll have to increase the variant to include all those subtypes, which IMHO defeats part of the purpose of making this "interface" (of course, we still get to inherit some shared things, but I'd like to not have to keep adding new classes into variant).
For now, I'm going to just do 1. But please let me know if there is something better.
Like other comments, if you store a vector of superclass by value, say vector<A>, as the vector allocates the memory, in addition to other information that vector stores, it will allocate sizeof(A)*NumOfElement(vector<A>) for storage. As subclasses, say B need more space than A, object slicing will occur. My suggestion is, instead of storing the class as value, store those as reference. ex)vector<shared_ptr<A>>. As the size of the pointer is same, this will allow to store A's subclasses. Oh, do not forget to define its virtual destructor!
Suggested code:
#include <iostream>
#include <vector>
#include <memory>
class Item {
public:
Item() : name("Book1") {}
std::string name;
virtual void f1() {/* Your Implementation here or make it pure virtual */};
virtual ~Item() = 0;
};
class Item2 : public Item {
public:
Item2() { name = "Book2"; }
//std::string name; //Hides base class name
void f1() override {/* Your Implementation here */};
~Item2() = default;
};
class Library {
public:
std::vector<std::shared_ptr<Item>> books;
void setToItem2() {
books.emplace_back(std::dynamic_pointer_cast<Item>(std::shared_ptr<Item2>(new Item2()))); //If you wish, use loop here
books.emplace_back(std::dynamic_pointer_cast<Item>(std::shared_ptr<Item2>(new Item2())));
}
void printBooks() {
for (auto& entry : books) {
std::cout << entry->name;
}
}
};
int main() {
Library a;
a.printBooks();
return 0;
}
The blessed way to store polymorphic instances in a container is to use std::unique_ptr. The container is still the sole owner of the object, but that pattern does not suffer the object slicing problem.
Furthermore your class hierarchy is weird: an Item2 instance will contain two versions of name. One (not directly accessible) in its Item base class and one directly accessible. It should at least be:
class Item2 : public Item {
public:
using Item::name;
Item2() {
name = "Book2";
}
};
But at construction time, name will first receive "Book1" at the base class initialization time, and then "Book2". So the normal way would be to build a base class like:
class BaseItem {
protected:
std::string name;
BaseItem(const std::string & name) : name(name) {};
virtual ~BaseItem() = default;
};
class Item: public BaseItem {
public:
using BaseItem::name;
Item() : BaseItem("Book1") {}
};
You can now build your Library class:
class Library {
public:
std::array<std::unique_ptr<BaseItem>, 2> books;
void printBooks() {
for (auto& entry : books) {
std::cout << entry->name;
}
}
};
Alternatively if you want to stick to a swapping pattern, you should use a variant:
class Library {
public:
std::variant<std::array<Item, 2>, std::array<Item2, 2> > books = std::array<Item, 2>();
void setToItem2() {
books = std::array<Item2, 2>();
}
void printBooks() {
auto *b = std::get_if< std::array<Item, 2> >(&books);
if (nullptr != b) {
for (auto& entry : *b) {
std::cout << entry.name << "\n";
}
}
else {
auto* b2 = std::get_if< std::array<Item2, 2> >(&books);
for (auto& entry : *b2) {
std::cout << entry.name << "\n";
}
}
}
};
int main() {
Library a;
a.printBooks();
a.setToItem2();
a.printBooks();
return 0;
}
Given the following type hierarchy
class Base { public: virtual ~Base(); }
class OurDervied : public Base {}
class TheirDerived : public Base {}
class General { public: virtual ~General(); }
class MySpecial : public General {};
class YourSpecial : public General {};
I have a function f(Base *bp).
In f, I want to create an object with type that depends on the type passed in. For example, f creates a MySpecial when receiving an instance of OurDerived, and creates a YourSpecial when receiving an instance of TheirDerived.
I think I can do this with dynamic_cast. It probably requires trying to cast the received object repeatedly until a match is found (non-nullptr returned).
Another option is giving OurDerived, TheirDerived, etc a unique tag and then use a switch case construct to create MySpecial, YourSpecial, etc.
Are there any other options for mapping class types in C++?
Manual Type Switching
If the types you want to create have no common ancestor, you have no other option but use a
if (dynamic_cast<const DerivedA *>(&base))
{
// Create an object of some type.
}
else if (dynamic_cast<const DerivedB *>(&base))
{
// Create an object of some other type.
}
else if (dynamic_cast<const DerivedC *>(&base))
{
// Create an object of yet aother type.
}
else
{
// Handle the case that no type was matched. Maybe use a default or
// issue an error.
}
cascade and there is no direct way you can return the created object because a function cannot decide at run-time what return type it wants to have. The only way out would be to use type erasure or ugly unions.
Lookup Table with Factory Functions
Fortunately, this is not what you have to do if all the types you want to create are derived from a common base class, as you have indicated in the comments. In this case, you can map the typeid of an object to a factory function that creates the appropriate object. As usual with run-time polymorphism, this requires a heap allocation.
void
take_action(const Base& base)
{
using FactoryT = std::function<std::unique_ptr<General>()>;
static const std::map<std::type_index, FactoryT> factories {
{typeid(DerivedA), [](){ return std::make_unique<Special1>(); }},
{typeid(DerivedB), [](){ return std::make_unique<Special2>(); }},
{typeid(DerivedC), [](){ return std::make_unique<Special3>(); }},
};
const auto o_uptr = factories.at(typeid(base))();
// Use the object. It can also be returned.
}
I have made the std::map<std::type_index, std::function<FactoryT()>> static so it is created only once for the entire run-time of the program. It is not clear whether or not this is beneficial in your particular situation. Maybe benchmark it.
Here is a complete working example.
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <typeindex>
#include <typeinfo>
struct Base
{
virtual ~Base() = default;
virtual std::string
name() const
{
return "Base";
}
};
std::ostream&
operator<<(std::ostream& os, const Base& base)
{
return os << base.name();
}
template<char Token>
struct Derived : Base
{
virtual std::string
name() const override
{
std::string name {"Derived"};
name += Token;
return name;
}
};
using DerivedA = Derived<'A'>;
using DerivedB = Derived<'B'>;
using DerivedC = Derived<'C'>;
struct General
{
virtual ~General() = default;
virtual std::string
name() const
{
return "General";
}
};
template<char Token>
struct Special : General
{
virtual std::string
name() const override
{
std::string name {"Special"};
name += Token;
return name;
}
};
std::ostream&
operator<<(std::ostream& os, const General& general)
{
return os << general.name();
}
using Special1 = Special<'1'>;
using Special2 = Special<'2'>;
using Special3 = Special<'3'>;
void
take_action(const Base& base)
{
using FactoryT = std::function<std::unique_ptr<General>()>;
static const std::map<std::type_index, FactoryT> factories {
{typeid(DerivedA), [](){ return std::make_unique<Special1>(); }},
{typeid(DerivedB), [](){ return std::make_unique<Special2>(); }},
{typeid(DerivedC), [](){ return std::make_unique<Special3>(); }},
};
const auto o_uptr = factories.at(typeid(base))();
std::cout << base << " was mapped to " << *o_uptr << std::endl;
}
int
main()
{
take_action(DerivedA {});
take_action(DerivedB {});
take_action(DerivedC {});
return 0;
}
Output:
DerivedA was mapped to Special1
DerivedB was mapped to Special2
DerivedC was mapped to Special3
Visitor Pattern
Of course, you should ask yourself the question why you actually want to do this. There are for sure legitimate applications of this technique but taking an abstract type and then taking action based on its dynamic type is usually a sign of over-abstraction and makes for poorly maintainable code. Did you consider adding the factory directly to Base?
struct Base
{
virtual ~Base() = default;
virtual std::unique_ptr<General>
getDealer() = 0;
// ...
};
The Derived classes can then override getDealer to do what the factories lambdas did in the above example.
If this seems to intrusive (maybe the Base class shouldn't know anything about the General class at all), you could consider using the visitor pattern. It is a bit more work but allows for better decoupling. There is plenty of information available on this pattern so I'll only show its application to your specific problem and refer you to your favorite search engine if you need more explanation.
#include <iostream>
#include <memory>
#include <string>
struct BaseVisitor;
struct Base
{
virtual ~Base() = default;
virtual void
accept(BaseVisitor&) const = 0;
virtual std::string
name() const
{
return "Base";
}
};
std::ostream&
operator<<(std::ostream& os, const Base& base)
{
return os << base.name();
}
template<char Token>
struct Derived : Base
{
virtual void
accept(BaseVisitor& vtor) const override;
virtual std::string
name() const override
{
std::string name {"Derived"};
name += Token;
return name;
}
};
using DerivedA = Derived<'A'>;
using DerivedB = Derived<'B'>;
using DerivedC = Derived<'C'>;
struct BaseVisitor
{
virtual ~BaseVisitor() = default;
virtual void
visit(const DerivedA&) = 0;
virtual void
visit(const DerivedB&) = 0;
virtual void
visit(const DerivedC&) = 0;
};
// Cannot be defined earlier because we need the complete type of BaseVisitor.
template<char Token>
void
Derived<Token>::accept(BaseVisitor& vtor) const
{
vtor.visit(*this);
}
struct General
{
virtual ~General() = default;
virtual std::string
name() const
{
return "General";
}
};
template<char Token>
struct Special : General
{
virtual std::string
name() const override
{
std::string name {"Special"};
name += Token;
return name;
}
};
std::ostream&
operator<<(std::ostream& os, const General& general)
{
return os << general.name();
}
using Special1 = Special<'1'>;
using Special2 = Special<'2'>;
using Special3 = Special<'3'>;
void
take_action(const Base& base)
{
struct Mapper : BaseVisitor
{
std::unique_ptr<General> uptr {};
virtual void
visit(const DerivedA&) override
{
this->uptr.reset(new Special1 {});
}
virtual void
visit(const DerivedB&) override
{
this->uptr.reset(new Special2 {});
}
virtual void
visit(const DerivedC&) override
{
this->uptr.reset(new Special3 {});
}
};
Mapper visitor {};
base.accept(visitor);
std::cout << base << " was mapped to " << *visitor.uptr << std::endl;
}
int
main()
{
take_action(DerivedA {});
take_action(DerivedB {});
take_action(DerivedC {});
return 0;
}
Note how we have nicely broken the coupling between Base and General. On the down side, we had to introduce some kind of parent-to-child dependency via the BaseVisitor class.
This solution also gets completely rid of any explicit run-time type inference and elegantly lets the dynamic dispatch machinery do all the magic behind the scenes.
Yes, you can delegate type mapping to derived classes:
class Base
{
public:
virtual General* map() = 0;
};
class OurDerived: public Base
{
protected:
General* map()
{
// compute Type* for OurDerved
}
};
class TheirDerived: public Base
{
protected:
General* map()
{
// compute Type* for TheirDerived
}
};
It's hard to say without knowing what responsibilities your function has, or how you feel about coupling {My|Your}Special to {Our|Their}Derived.
Is Base constructible? Is Base or its derived classes allowed to have virtual methods? If you already incurred the cost of a vtable, I would delegate the responsibility to the derived types themselves, and explicitly make the method abstract on Base to force each derivation to explain itself in this regard.
Are MySpcial / YourSpecial related in the type hierarchy? Otherwise you are better off experimenting with explicit template instantiations of a helper function.
I have a problem which I encounter again and again in a similar way.
For example:
I have an abstract base class which acts as interface for a series of concrete classes which act as, let's say, data containers.
class DataInterface
{
public:
DataInterface();
~DataInterface();
virtual void FetchData(void) = 0;
virtual void ProcessData(void) = 0;
virtual void ClearData(void) = 0;
}
The concrete classes would look like this:
class BinaryData: public DataInterface
{
public:
BinaryData();
~ BinaryData();
virtual void FetchData(void);
virtual void ProcessData(void);
virtual void ClearData(void);
private:
bool m_boolData;
}
class IntegerData: public DataInterface
{
public:
IntegerData();
~ IntegerData();
virtual void FetchData(void);
virtual void ProcessData(void);
virtual void ClearData(void);
private:
int m_intData;
}
The subclasses implement the interface which they inherited from DataInterface. But they have different attributes to hold their data. So far so good.
I can use the classes in the main function like that:
int main()
{
int IntegerData;
bool BoolData;
DataInterface *pData1 = new BinaryData();
DataInterface *pData2 = new IntegerData();
pData1->FetchData();
pData2->FetchData();
pData1->ProcessData();
pData2->ProcessData();
// now I want to get the data of pData1 and pData2, for example to write it into a file, show in visualization, ...
IntegerData = pData2->GetData() ????
BoolData = pData1->GetData() ????
}
Now comes the problem:
How do I get the data from the concrete classes? I have only base class pointers, so I would need to define an abstract getter method in DataInterface. But the signature of the getter method wouold vary from subclass to subclass. For example one time I need to return an integer, one time I need to return a bool type.
Please give me a hint, this problem drives me nuts :/
Make a non-virtual GetData() member on each derived class. Then, if you know for certain the actual class of your objects, you can simply perform a static cast and call GetData():
int intData = static_cast<IntegerData*>(pData2)->GetData();
If you don't know the class, then you need to perform a dynamic cast and check its result:
if (IntegerData* _pData2 = dynamic_cast<IntegerData*>(pData2))
{
int intData = _pData2->GetData();
// Do stuff with the int
}
else if (BinaryData* _pData2 = dynamic_cast<BinaryData*>(pData2))
{
bool binaryData = _pData2->GetData();
// Do stuff with the bool
}
If you want to pass your data to another entity, you need an abstraction of it.
There are 2 common ways to achieve this:
1:
Use void*.
class DataInterface
{
public:
...
virtual void* GetData() = 0;
};
class BinaryData: public DataInterface
{
public:
virtual void* GetData() { return &m_boolData; }
private:
bool m_boolData;
};
In main use it like this:
int main()
{
bool BoolData;
DataInterface *pData1 = new BinaryData();
pData1->FetchData();
pData1->ProcessData();
BoolData = *(bool*))pData1->GetData());
}
Advantage of this approach is in its simplicity.
Disadvantages are direct access to internal of an object (breaking encapsulation) and also misuse of polymorphism (why do you need an interface if you eventually cast to a type related to a concrete derivative?)
2:
A more robust way is to not send the raw data to a client from out of your concrete object but to make a communication with clients an additional role of the object.
class DataInterface
{
public:
...
virtual void SendData() = 0;
};
class BinaryData: public DataInterface
{
public:
...
virtual void SendData()
{
//do your stuff here, you know the exact type of your data
}
};
int main()
{
bool BoolData;
DataInterface *pData1 = new BinaryData();
pData1->FetchData();
pData1->ProcessData();
pData1->SendData();
}
Note, this is a very stripped example but it demonstrates the idea. Normally, in a real use case you would register clients with you class and send the data to them via a defined interface.
I am not really sure this is a "good" practice but here is one way to solve this.
One advantage with this is that if you try to get the wrong type of data you can get custom error messages. And you can avoid casts (I am not a fan of them).
class DataInterface
{
public:
DataInterface();
~DataInterface();
virtual void FetchData(void) = 0;
virtual void ProcessData(void) = 0;
virtual void ClearData(void) = 0;
virtual int getIntData() { // Error message }
virtual bool getBoolData() { // Error message }
};
class BinaryData: public DataInterface
{
public:
BinaryData();
~ BinaryData();
virtual void FetchData(void);
virtual void ProcessData(void);
virtual void ClearData(void);
virtual int getIntData() { // Error message }
virtual bool getBoolData() { return m_boolData; }
private:
bool m_boolData;
}
class IntegerData: public DataInterface
{
public:
IntegerData();
~ IntegerData();
virtual void FetchData(void);
virtual void ProcessData(void);
virtual void ClearData(void);
virtual int getIntData() { return m_intData; }
virtual bool getBoolData() { // Error message }
private:
int m_intData;
}
int main()
{
int IntegerData;
bool BoolData;
DataInterface *pData1 = new BinaryData();
DataInterface *pData2 = new IntegerData();
pData1->FetchData();
pData2->FetchData();
pData1->ProcessData();
pData2->ProcessData();
// now I want to get the data of pData1 and pData2, for example to write it into a file, show in visualization, ...
IntegerData = pData2->GetIntData();
BoolData = pData1->GetBoolData();
BoolData = pData2->GetBoolData() // This will tell you that you are trying to get bool from int class.
}
Here is one way of handling it with templates.
using namespace std;
template<typename T>
class DataInterface
{
public:
DataInterface(T d) : data(d) {}
virtual T GetData() = 0;
protected:
T data;
};
class BinaryData : public DataInterface<bool>
{
public:
BinaryData(bool b) : DataInterface<bool>(b) {}
virtual bool GetData() {return data;}
};
class IntegerData: public DataInterface<int>
{
public:
IntegerData(int i) : DataInterface<int>(i) {}
virtual int GetData() {return data;}
};
int main()
{
int myint;
bool mybool;
DataInterface<bool> *pData1 = new BinaryData(true);
DataInterface<int> *pData2 = new IntegerData(1);
// now I want to get the data of pData1 and pData2, for example to write it into a file, show in visualization, ...
myint = pData2->GetData();
mybool = pData1->GetData();
cout<<myint<<" "<<mybool<<endl;
}
A very simple way of achieving this is to design your base class so that it returns a variant type. A variant is a discriminated union container, which holds an object from an heterogeneous set of types (see http://www.boost.org/doc/libs/1_59_0/doc/html/variant.html). Here is a complete example:
#include <iostream>
#include <algorithm>
#include <boost/variant.hpp>
#include <memory>
using namespace std;
class DataInterface
{
public:
DataInterface(){};
virtual ~DataInterface(){};
virtual void FetchData(void) = 0;
virtual void ProcessData(void) = 0;
virtual void ClearData(void) = 0;
virtual boost::variant<bool,int,double,std::string> GetData()=0;
};
class IntResult : public DataInterface{
public:
IntResult() : resultInt(0){};
~IntResult(){};
virtual void FetchData() override {resultInt = 10;};
virtual void ProcessData() override {resultInt *= 10;}
virtual void ClearData() override {resultInt = 0;};
virtual boost::variant<bool,int,double,std::string> GetData()override{
return resultInt;
};
private:
int resultInt;
};
class StringResult : public DataInterface{
public:
StringResult() : resultString(""){};
~StringResult(){};
virtual void FetchData() {
resultString= "Hello World";
}
virtual void ProcessData() override {
std::transform(resultString.begin(), resultString.end(),resultString.begin(), ::toupper);
}
virtual void ClearData() override {resultString = "";}
virtual boost::variant<bool,int,double,std::string> GetData() override {
return resultString;
};
private:
std::string resultString;
};
int main() {
DataInterface* data;
IntResult* intResult = new IntResult;
StringResult* stringResult = new StringResult;
data = intResult;
data->FetchData();
data->ProcessData();
switch(data->GetData().which()){
case 0:
std::cout << "found bool: " << boost::get<bool>(data->GetData()) << std::endl;
break;
case 1:
std::cout << "found int: " << boost::get<int>(data->GetData()) << std::endl;
break;
case 2:
std::cout << "found double: " << boost::get<double>(data->GetData()) << std::endl;
break;
case 3:
std::cout << "found string: " << boost::get<std::string>(data->GetData()) << std::endl;
break;
default:
break;
}
data = stringResult;
data->FetchData();
data->ProcessData();
switch(data->GetData().which()){
case 0:
std::cout << "found bool: " << boost::get<bool>(data->GetData()) << std::endl;
break;
case 1:
std::cout << "found int: " << boost::get<int>(data->GetData()) << std::endl;
break;
case 2:
std::cout << "found double: " << boost::get<double>(data->GetData()) << std::endl;
break;
case 3:
std::cout << "found string: " << boost::get<std::string>(data->GetData()) << std::endl;
break;
default:
break;
}
delete intResult;
delete stringResult;
return 0;
}
Note that in your case a bool is implicitly convertible to an int so you could simply return ints all the time. The variant approach would work if you need to return truly heterogeneous types. Equivalently you could return a boost any, which can also lets you manipulate a heterogeneous union of types uniformly (see http://www.boost.org/doc/libs/1_59_0/doc/html/any.html). Finally if you don't want any dependencies on boost, it is not terribly difficult to roll out your own variant type, which can hold discriminate set of types.
I have a hirerchy of Message class and Processor class. Each processor can recieve one or more messages on the fly. As each message can have some differnt attributes, I've to downcast that message to the concrect message class, to actually process that.
As there are a no. of message classes and process classes, I don't want to use dynamic_cast.
I tried to use following code, but this is giving compile time error.
Also, I have the flexibility to attach a processor pointer with a message (if needed), but not the other way round.
class Message
{
public:
virtual const Message* const getMessage() const = 0;
};
class MA : public Message
{
public:
const MA* const getMessage() const {return this;}
void printMA() const{std::cout<<"I am MA"<<std::endl;}
};
class MB : public Message
{
public:
const MB* const getMessage() const {return this;}
void printMB() const{std::cout<<"I am MB"<<std::endl;}
};
class Processor
{
public:
virtual void process(const Message* m) = 0;
};
class PA : public Processor
{
public:
void process(const Message* m) {processM(m->getMessage());}
void processM(const MA* m) {m->printMA();}
void processM(const MB* m) {m->printMB();}
};
int main()
{
Message* m1 = new MA();
Message* m2 = new MB();
Processor* p1 = new PA();
p1->process(m1);
p1->process(m2);
return 0;
}
I used 'double dispatch' finally to get around this. Now, the only thing is that I need to add a function in MessageProcessor' class, whenever i add a new message type., but i think that is fine.
class MessageProcessor
{
public:
virtual void process(const MA*) const{std::cout<<"unhandled:MA"<<std::endl;}
virtual void process(const MB*) const{std::cout<<"unhandled:MB"<<std::endl;}
virtual void process(const MC*) const{std::cout<<"unhandled:MC"<<std::endl;}
};
class Message
{
public:
virtual void process(const MessageProcessor*) const = 0;
};
class MA : public Message
{
public:
void printMA() const{std::cout<<"I am MA"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class MB : public Message
{
public:
void printMB() const{std::cout<<"I am MB"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class MC : public Message
{
public:
void printMC() const{std::cout<<"I am MC"<<std::endl;}
virtual void process(const MessageProcessor* p) const {p->process(this);}
};
class Processor : public MessageProcessor
{
public:
void processM(const Message* m){m->process(this);}
};
class PA : public Processor
{
public:
void process(const MA* m) const {m->printMA();}
void process(const MB* m) const {m->printMB();}
};
class PB : public Processor
{
public:
void process(const MA* m) const {m->printMA();}
void process(const MC* m) const {m->printMC();}
};
int main()
{
const Message* m1 = new MA();
const Message* m2 = new MB();
const Message* m3 = new MC();
Processor* p1 = new PA();
p1->processM(m1);
p1->processM(m2);
p1->processM(m3);
Processor* p2 = new PB();
p2->processM(m1);
p2->processM(m2);
p2->processM(m3);
return 0;
}
The most general solution to your problem is probably the Visitor pattern.
The simplest thing to do is eliminate the getMessage() method, and make the print() pure virtual in Message and override this in MA and MB. Furthermore, you can make process() a pure virtual method in Process and override this in PA. See code below:
#include <iostream>
class Message
{
public:
const std::string _id;
Message(std::string id):_id(id) {}
virtual void print() const = 0;
virtual void other_fun() const = 0;
};
class MA : public Message
{
private: double d_;
public:
MA():Message("MA"), d_(0.0) {}
virtual void print() const
{
std::cout<<"I am MA"<<std::endl;
std::cout << "I also have a double" << std::endl;
}
virtual void other_fun() const { std::cout << "I am MA specific" << std::endl; }
void do_hoops () const { std::cout << "Hoop!"<<std::endl;}
};
class MB : public Message
{
private: int i_;
public:
MB():Message("MB"), i_(0) {}
virtual void print() const
{
std::cout<<"I am MB"<<std::endl;
std::cout << "I also have an int"<<std::endl;
}
virtual void other_fun() const { std::cout << "I am MB specific" << std::endl; }
void do_twist() const { std::cout << "Twist!"<<std::endl; }
};
class Processor
{
public:
const std::string _id;
Processor(std::string id) : _id(id){}
virtual void process(const Message* m) = 0;
};
class PA : public Processor
{
public:
PA():Processor("PA") {}
virtual void process(const Message* m)
{
m->print();
m->other_fun();
}
};
int main()
{
Message* m1 = new MA();
Message* m2 = new MB();
// generic handling of message
Processor* p1 = new PA();
p1->process(m1);
p1->process(m2);
// message specific stuff
dynamic_cast<MA*>(m1)->do_hoops();
dynamic_cast<MB*>(m2)->do_twist();
return 0;
}
Output on Ideone.
No casts are required, the virtual functions will be selected at runtime through dynamic dispatch (virtual table lookup etc.). Message and Process are abstract base classes ("interfaces") and MA, MB and PA are concrete classes implementing these interfaces. Ideally, you also would factor the std::string state out of the Message interface, but that's left as an exercise.
Casting would be required if you would call functions that are specific to a derived class, and if you know at runtime that you are in fact calling such a class. This is done through a dynamic_cast to the particular derived class your base class pointer is currently pointing to.
You have a design flaw. Signature of Processor::process suggests it takes a Message, then it should not break this promise by trying to access something that is not a public interface of Message.
You can make Process a template class (host) that inherits from user supplied policies. Policies here are the concrete Message classes. Something like this:
#include <iostream>
struct MA
{
void print ()
{
std::cout << "MA: I'm the interface" << std::endl;
}
void printMA ()
{
std::cout << "MA: I'm special" << std::endl;
}
};
struct MB
{
void print ()
{
std::cout << "MB: I'm the interface" << std::endl;
}
void printMB ()
{
std::cout << "MB: I'm special" << std::endl;
}
};
template <typename M>
struct Process :
public M
{
void process()
{
M::print();
}
};
int main ()
{
Process<MA> p1;
Process<MB> p2;
p1.print(); // MA: I'm the interface
p1.printMA(); // MA: I'm special
p2.print(); // MB: I'm the interface
p2.printMB(); // MB: I'm special
}
Policies have print method that defines its interface. They also have some special methods like printMA and printMB. Host class (here Process) acts as user's interface to the policies. It can use the interface methods from policy classes. Special policy methods can be invoked by the user through host class.
You've run into a limitation of C++. What you really want is for the polymorphism to work on the arguments to a method, not just the method that the arguments are called on. It's generally referred to as double dispatch. Unfortunately, while there are some kind-of work-arounds, I haven't seen any perfect ones. That Wikipedia article shows the generally accepted workaround (using the Visitor pattern).
I think I messed up somehow in my design because I want to keep a vector of various object types. These types all share a common base class. Example:
Class Buick: AmericanCar
{
}
Class Ford: AmericanCar
{
}
then I did:
vector<AmericanCar*> cars_i_own;
Now, I have my vector of pointers but I don't have the derived class which is what I need. I thought about adding a GetType/SetType function to the base class and then use a dynamic cast. This is clunky though. Did i use the wrong design for this?
Well, what are you trying to do with it? Get the name or cost? You would have something like:
class Car
{
public:
virtual ~Car(void) {}
virtual std::string location(void) const = 0;
virtual std::string name(void) const = 0;
virtual double cost(void) const = 0;
}
class AmericanCar
{
public:
virtual ~AmericanCar(void) {}
virtual std::string location(void) const
{
return "America";
}
}
class Buick : public AmericanCar
{
public:
virtual std::string name(void) const
{
return "Buick";
}
virtual double cost(void) const
{
return /* ... */;
}
}
class Ford : public AmericanCar
{
public:
virtual std::string name(void) const
{
return "Ford";
}
virtual double cost(void) const
{
return /* ... */;
}
}
Now you can call these methods polymorphically.
This is somewhat strange, though. You don't need a different class to store names and cost like this:
class Car
{
public:
Car(const std::string& pLocation,
const std::string& pName,
double pCost) :
mLocation(pLocation),
mName(pName),
mCost(pCost)
{
}
const std::string& location(void) const
{
return mLocation;
}
void location(const std::string& pLocation)
{
mLocation = pLocation;
}
const std::string& name(void) const
{
return mName;
}
void name(const std::string& pName)
{
mName = pName;
}
const double cost(void) const
{
return mCost;
}
void cost(double pCost)
{
mCost = pCost;
}
private:
std::string mLocation;
std::string mName;
double mCost;
}
// make cars
std::vector<Car> cars;
cars.push_back(Car("America", "Buick", /* ... */));
The purpose of inheritance / polymorphism is so you don't need to care which derived type you are dealing with.
In particular I think storing data, such as make of car, country of origin etc, encoded in a class hierarchy doesn't seem to be particularly beneficial. Does an AmericanCar do something fundamentally different from, say, a Japanese car (other than consuming more fuel, which again can be better stored in a data member)?
Why do you need to know the derived class? Normally you would have virtual functions to take care of any behavior differences between the two derived classes.
The goal is that the code using the parent class shouldn't have to know the exact class it's working with.
You can use typeid to determine the derived class:
struct Base
{
virtual ~Base() {}
};
struct Derived : public Base { };
int main()
{
Base* b = new Derived();
std::cout << typeid(*b).name() << std::endl;
}
This outputs: "Derived".
But, usually with polymorphism the point is that you shouldn't be concerned with this. You simply call a base-class member function and the proper derived-class member function is called at runtime.