I have a derived class and a base class that both override the same virtual function. How can I pass some other function a pointer or reference to an instance of the derived class, but still call the base class's version of the virtual function?
I appear to have precisely the opposite problem from this question. I effectively want to slice my derived object so that it looks like a base object (assuming I can do so safely), but can't figure out how to do it.
I have a large set of data that would be expensive to copy, so I instead pass around a lightweight view
object that allows iteration. I have an interface that various datasets inherit to advertise that they can provide a view
:
class data_interface
{
virtual view get_view() = 0;
};
There's a base class that owns one of these datasets, and can provide a view to it on request:
class base_owns_data : public data_interface
{
public:
view get_view() override
{
return view(d);
}
private:
data d;
};
That class works fine in isolation. My application does things like pass it by reference to free functions, in order to get a more complex view into the data:
view some_process(base_owns_data &b)
{
auto working_view = b.get_view();
// Do a bunch of things to filter the view
return working_view;
}
(Please note that the above is stripped down for the MCVE - here, it would make more sense to directly take a view
parameter, but in context I'm combining several datasets and one of them needs to own the storage rather than just having view to it)
The problem appears when I try to extend the base dataset with another that needs to do some extra processing. Here's a derived class:
class derived_owns_data : public base_owns_data
{
public:
base_owns_data& as_base()
{
return *this;
}
view get_view() override
{
return some_process(this->as_base());
}
};
What I wanted to happen is that, since some_process
is being passed a reference to base_owns_data
, that base_owns_data::get_view()
would be called in some_process
.
What actually happens is that some_process
still calls derived_owns_data::get_view()
. This results in an infinite loop as those two functions call each other back and forth.
I'm not sure what to do - I can't remove virtual
from the interface, or the interface becomes useless. I don't want to copy the data, either. But I can't figure out how to force base_owns_data::get_view()
to be called on a reference of type derived_owns_data
.
I tried passing a pointer instead of a reference, but that still seems to cause an infinite loop.
How can I safely make the derived class appear to be a base class in some_process
?
Full MCVE (or on ideone):
struct data
{
char c[100];
};
class view
{
public:
view(data d) :
first(&d.c[0]),
last(&d.c[100])
{
}
private:
char * first;
char * last;
};
class data_interface
{
virtual view get_view() = 0;
};
class base_owns_data : public data_interface
{
public:
view get_view() override
{
return view(d);
}
private:
data d;
};
view some_process(base_owns_data &b)
{
return b.get_view();
}
class derived_owns_data : public base_owns_data
{
public:
base_owns_data& as_base()
{
return *this;
}
view get_view() override
{
return some_process(this->as_base());
}
};
int main() {
derived_owns_data d;
d.get_view();
return 0;
}