Reputation: 3747
I have two classes A
(base) and B
(deriving from A
):
class A { };
class B : public A
{
int data;
public:
int get_data() { return data; }
};
Now I have a function test which takes base class pointer and calls derived class function :
void test(A * ptr)
{
ptr->get_data();
}
But problem is ptr
may point to A
's object or B
's object. If it points to B
's object, then OK, but if to A
's object, then it is a problem.
Moreover, I don't want to make get_data()
virtual because data
is not property of A
's object.
How can I check if ptr
points to B
's object? One solution which I can think is dynamic_cast
and check it for NULL
. Is it the best solution or can I have a better solution ?
Upvotes: 3
Views: 4266
Reputation: 2985
Inheritance models the is-a relationship. Clearly in your code B is not an A and inheritance is the wrong model. You mention in your comment that you have a vector which is being passed to an enclosing, bigger, function. I would suggest that one of the following would be a better fit:
1. std::vector<boost::any>
2. std::vector<boost::variant<A,B>>
Edit Here's an example using boost variant:
class A
{
public:
void DoIt()
{
std::cout << "did it!" << "\n";
}
};
class B
{
public:
void GetIt()
{
std::cout << "got it!" << "\n";
}
};
typedef boost::variant<A,B> ab_t;
typedef std::vector<ab_t> list_ab;
void test(list_ab& list)
{
std::for_each(std::begin(list), std::end(list), [](ab_t& item)
{
if(A* a = boost::get<A>(&item))
a->DoIt();
if(B* b = boost::get<B>(&item))
b->GetIt();
});
}
Upvotes: 0
Reputation: 5005
If you can change the interface of A
and B
(including adding virtual functions) and if you can re-shuffle the code in the test
function you can use the "visitor pattern". Here's a sample using the better named Base
and Derived
classes:
class Visitor
{
public:
void Visit(Base * B)
{
}
void Visit(Derived * D)
{
int data = D->get_data();
}
};
class Base
{
public:
virtual void Accept(Visitor * V )
{
V->Visit(this);
}
};
class Derived: public Base
{
public:
int get_data()
{
return data;
}
virtual void Accept(Visitor * V )
{
V->Visit(this);
}
private:
int data;
};
This way you can iterate over your vector of Base*
, call Accept
of each element and know that only for Derived
elements the get_data
method will be called.
Upvotes: 4
Reputation: 8350
You say that actually you have a vector of elements A or B, then your test function really looks like:
void test( A ** ptr )
Then you can use the overloading C++ capabilities to make a utility function, the right function will be called:
void test( A ** ptr ) {
A * elem;
int i=0;
elem = ptr[i++];
while(elem) {
testElement(elem);
elem = ptr[i++];
}
}
void testElement( A * ptr ) { }
void testElement( B * ptr ) {
ptr->get_data();
}
Upvotes: -4
Reputation: 110648
This means your test
function is lying. It is saying that it will accept a pointer to any A
object, even types derived from A
, but the function won't actually work for anything other than B
. You're much better off taking a B*
:
void test(B* ptr)
{
ptr->get_data();
]
Upvotes: 5