Reputation: 193
I have a little design problem.
Assume I have this interface:
class IBase {
public:
virtual void Run() = 0;
virtual void DoSomethingWithData(IData* data) = 0;
virtual ~IBase() = 0;
};
I want to implement derived classes, so I need to build a derived class for IData (let's call it DData). IData is basically an empty interface:
class IData {
public:
IData();
virtual ~IData() = 0;
};
The problem is that in DoSomethingWithData method that I implement - I need to refer to specific members in DData, but I can't because the pointer is of IData . For example, see implementation of DoSomethingWithData in some derived class:
class DData : public IData {
private:
int m_i;
};
<Derived.h : IBase>
Derived::DoSomethingWithData(IData* data) {
some_function_call(data->m_i) // cannot be used by the base ptr
}
What is the best way to overcome this problem?
dynamic cast on SetData? Changing the interface (in this way?)? Other option?
Edit:
To clarify the problem: I have this relation -
class A -> uses DataA
class B -> uses DataB
class C -> uses DataC
there is a common interface for the classes: Run, DoSomethingWithData. DoSomethingWithData expects for data, but it does not know what is the data, it depends in the class that we implement. I need to find the best way to write the interface, without using bad OOP techniques like dynamic_cast.
Upvotes: 2
Views: 320
Reputation: 193
The solution which we chose is using templates (I don't understand why no one suggested it).
template <class T>
class IBase {
public:
virtual void Run() = 0;
virtual void DoSomethingWithData(const T& data) = 0;
virtual ~IBase() = 0;
};
I think that this is the best solution in this case, since it does not requires anyone to derive from empty interface, and it does declare for some contruct.
I'd like to hear if someone has any reservation for this solution.
Upvotes: 0
Reputation: 24778
The problem is that in
DoSomethingWithData
method that I implement - I need to refer to specific members inDData
, but I can't because the pointer is ofIData
.
You are passing a pointer to IData
which is the base class of DData
. By means of virtual function dispatch you may call a member function that is is actually implemented in DData
through a pointer to IData
.
The class DData
derives from IData
, so you can declare a virtual member function in IData
:
class IData {
public:
IData();
virtual int getData() = 0; // <-- new virtual function
virtual ~IData() = 0;
};
and then implement this function in DData
:
class DData : public IData {
public:
int getData() override { // <-- implementation
return m_i;
}
private:
int m_i;
};
Since this member function is implemented in DData
, it can access its private data members (i.e.: m_i
).
When you call getData()
of a DData
instance through a IData
pointer, you will be using DData
's implementation.
Upvotes: 1
Reputation: 330
I need to refer to specific members in DData, but I can't because the pointer is of IData
Interfaces specify a contract. It does not "know" about internal details/representation (aka, things like member variables, private functions, etc.) If your IData
has to "know" about private member variables of DData
, you are doing something wrong. Perhaps using an interface for Data
is wrong. If Data
is meant to be a POD (plain ol' data) struct, then just have your base class take a Data
and expose an API that deals with said struct.
Upvotes: 1