Say we have a library which provides a class
struct Base { int foo() { return 42; } };
I cannot change that class.
99% of the people never want to override foo, hence it has not been made virtual by the library designers.
But I need to override it:
struct MyClass : Base { int foo() { return 73; } };
Even worse, the library has interfaces accepting pointers to Base.
I want to plug in MyClass, but of course, since foo is not virtual, the code behind the interface always calls Base::foo. I want it to call MyClass::foo.
What can I do about it? Is there a common pattern to make Base::foo appear to be virtual?
In reality, Base::foo is QAbstractProxyModel::sourceModel.
I'm implementing a ProxyChain, to abstract many proxy models to a single one.
QAbstractProxyModel::setSourceModel is virtual, but QAbstractProxyModel::sourceModel isn't and that makes a lot of trouble.
void ProxyChain::setSourceModel(QAbstractItemModel* source_model)
{
for (auto* proxy : m_proxies) {
proxy->setSourceModel(source_model);
source_model = proxy;
}
QIdentityProxyModel::setSourceModel(source_model);
}
QAbstractItemModel* ProxyChain::sourceModel() const
{
return m_proxies.front()->sourceModel();
}
What can I do about it?
Nothing.
This is why guidelines tell us to use virtual if we want other people to be able to "pretend" that their classes are versions of our classes.
The author of Base did not do that, so you do not have that power.
That's it.
What can I do about it?
Nothing. If a member function is non-virtual, then it is non-virtual. This means that any code, anywhere in the code base, which takes a Base pointer or reference who calls base->foo will be calling exactly and only Base::foo. This call is statically (compile-time) bound to the function it calls.
You cannot reach into someone else's code and make them use dynamic binding. If they didn't choose to participate in dynamic binding, then you can't make them. You can create your own derived class and write your own version of foo which hides the base class version. But this will not affect the behavior of any code which gets a pointer/reference to Base.
In your specific case, your best bet will be to make sure to call the base class setSourceModel with the object that you want sourceModel to return any time something changes which changes what sourceModel should return.
Related
I'm pretty experienced in C++, but I find myself struggling with this particular design problem.
I want to have a base class, that I can stuff in a std::map, with a virtual function that can be called generically by a method that is querying the map. But I want to be able to call that function from a base class pointer with different parameters, depending on what the derived type is. Something functionally similar to the following wildly illegal example:
class Base
{
virtual void doThing() = 0;
}
class Derived1 : public Base
{
void doThing(int i, const std::string& s) {} // can't do that
}
class Derived2: public Base
{
void doThing(double d, std::vector<int>& v) {} // can't do that either
}
enum class ID = {
DERIVED1,
DERIVED2
}
std::map<ID, std::unique_ptr<Base> thingmap = { ... }
std::unique_ptr<Base>& getThing(int) { return thingmap[i] };
int main(int I, const char* argv[]) {
auto baseptr = getThing(DERIVED1);
baseptr->doThing(42, "hello world");
}
I don't want the caller to have to know what the derived type is, only that a Derived1 takes an int and a string. Downcasting isn't an option because the whole point of this is that I don't want the caller to have to specify the derived type explicitly. And C-style variable argument lists are yucky. :-)
Edited to clarify: I know exactly why the above can't possibly work, thank you. :-) This is library code and I'm trying to conceal the internals of the library from the caller to the greatest extent possible. If there's a solution it probably involves a variadic template function.
You can't do that.
Your map is filled with Base instances, so the class DO NOT have the required prototypes implemented in Derived1 or Derived2... And redefining overloaded methods do not implement the pure virtual method doThing, so Derived1 and Derived2 are still abstract classes and therefore cannot be instanciated.
Worst, your getThing function only deals with Base, so the compiler would NEVER allows you to use the overloaded signatures, since they don't exist AT ALL in Base. There is nothing to know the real class behind, since you don't use templates and implicit template argument deduction.
Your pattern cannot be done this way, period. Since you don't want to use neither downcasting nor explicitely specified child classes, you're stuck.
Even if you add all possible prototypes in Base, since it will be pure virtual methods, both derived classes will still be abstract classes. And if they aren't, then you'll never be able to know which one is a NOP and which one is implemented, since it will requires downcasting!
I think that you made a common mistake, even done by expert developers sometimes: you went into conception directly, BEFORE determining your real ROOT needs.
What you ask looks like the core system of a factory, and it's really not the good way to implement this design pattern and/or designing the specialized derived classes.
I have a base class that clients can "shut down":
struct base {
void shutdown() {
//code
}
};
But clients can (if they want) create a subclass to suit their own needs:
struct der : public base {
void shutdown(double some, int other, bool parameters) {
//custom shutdown stuff
base::shutdown(); //<- thus MUST be called
}
};
The problem is that the client must remember to call base::shutdown() (the superclass creator will document this to subclass developers). This seems error-prone, as nothing is enforced at compile-time.
Are there alternative design patterns to solve this in some way?
Unfortunately, this is one of those cases where you "have to do the right thing" when writing the code. This applies to many things in programming. If you don't do the right calculations when calculating something, that's also wrong. Or if you call a function twice that should only be called once. Or not calling it at all when it has to be called. All of these things are "doing it wrong". You can't prevent programmers from making mistakes...
Of course, if you hadn't added a bunch of extra parameters, you could do it "in reverse" by having a non-virtual function in the base-class that doesn't get overridden, and then let the base-class call a virtual function in the derived class. As I said, it doesn't work if you have parameters that aren't present in the base class that needs to go into the derived class.
An example of what I mean:
struct base {
void shutdown() final { // final: it can't be overridden in derived class
do_shutdown(); // Calls derived function's
// ... more code here ...
}
virtual void do_shutdown() { } // default is "do nothing".
};
struct der: public base
{
// not overriding `shutdown`, but overriding `do_shutdown`
void do_shutdown()
{
.. some code goes here ..
}
}
Now the call to der->shutdown() will call the base-class's implementation, which calls do_shutdown in the derived class before completing the in the base-class's shutdown.
However, like I said, you can't add extra parameters when you do this - in fact, deriving a class and changing the parameters is "wrong" - not so wrong you can't possibly ever do it, but it tends to be a bad thing when using inheritance polymorphism, because the whole purpose of polymorphism is that there is some common code that "doesn't know if it's a base class object, a derived1 object or a derived2 object" - so if it needs to know which kind of object to pass the correct number of arguments, it gets a bit meaningless.
I wouldn't worry about it. It's similar to the assignment operator of derived classes. It's not your fault if the subclass developer forgets to call it, but it's not an error if it isn't either.
C++ FAQ entry on the subject
I'm using class to declare interface. I just want to define method signature. This method must be implemented in any non-abstract subclass. I don't need method to be virtual. This is default behaviour in C# BTW (i came from C#/Java world)
However it seems in C++ it is not possible. I either declare method in regular way
void Foo::Method()
and then it is not mandatory to implement it or declare method as "pure virtual"
void virtual Foo::Method() = 0;
and then method become virtual, but I want to avoid this to save performance a little bit.
It seems I want to have something like that
void Foo::Method() = 0;
but that would be compilation error
if you're planning on using the derived class from template code, i.e. compile time polymorphism, then you only need to document the expected signature
the code using a derived class simply won't compile and link if the used function isn't implemented
otherwise, for runtime polymorphism it needs to be virtual, or else it won't be called
I believe that you might be confused with regard to how C# version works:
class A {
public void NonVirt() { Console.Out.WriteLine("A:NonVirt"); }
public virtual void Virt() { Console.Out.WriteLine("A:Virt"); }
}
class B : A {
public void NonVirt() { Console.Out.WriteLine("B:NonVirt"); }
public override void Virt() { Console.Out.WriteLine("B:Virt"); }
}
class Program {
static void Main(string[] args) {
A x = new B();
x.NonVirt();
x.Virt();
}
}
This will output
A:NonVirt
B:Virt
So even in C#, you need to make method virtual if you want to call the derived implementation.
If method must be implemented in all non-abstract subclasses this means that you need to call them through base class pointer. This in turn means that you need to make them virtual, same as in C# (and likely in Java, but I am not sure)
Btw, price of virtual call is a few nanoseconds on modern CPUs, so I am not sure if it is worth it but lets say that it is.
If you want to avoid the cost of virtual call, you should use compile time polymorphism via templates
There is no notion of interface in C++. The only way to achieve your goal is to create a base class defining as virtual and = 0 all the methods which must be actually defined in subclasses.
class IBase {
// ...
virtual void f1() = 0;
// ....
}
That class will be virtual pure if all methods are defined like f1, which is the closest to an interface you can get.
The concept of interface in Java is a bit like a contract with regard to classes implementing it. The compiler enforces the constraints of the contract by checking the content of the implementors. This notion of contract or explicit structural subtyping does not exist formally in C++.
However, you can manually verify that such constraints are respected by defining a template wich will expect as a parameter a class with the defined methods or attributes, and using that template on the classes to be verified. This could be considered a form of unit testing I suppose.
I'm extending a class provided by a third part library. The class, let's call it Foo, has a reset() method which can be called in order to restart Foo's behavior. The reset() method is also used internally by the class.
class Foo
{
public:
void reset () {
/* ... */
}
void something () {
reset();
}
};
So far, I need to overload the reset() method in order to reset my additional features as well:
class Bar : public Foo
{
public:
void reset() {
/* ...something... */
Foo::reset();
}
};
Unfortunately, since the Foo::reset() method is not virtual, by calling Bar::something() I get the Foo::reset() method called instead of Bar::reset().
Is there a way (different from overloading Foo::something() as well) to make it backward-virtual?
You cannot extend classes that were not intended to be extended.
You can't make reset() virtual in your library in such a way that it will affect the base class without changing the base class's code. For starters, the compiler has not added the necessary bookkeeping code that allows it to make virtual calls to reset().
There is no 'clean way' of doing it using inheritance. Virtual is a compile/link time difference: using a vtable to resolve method at runtime (virtual) vs direct linking (non-virtual).
No this is not possible. The virtualness of a method is decided when the method is declared and you cannot change it later in a base class.
To allow you to do so would be nothing short of a disaster. Virtual methods simply behave differently than non-virtual methods and it must be accounted for when designing an object. With this proposal I would have to consider that all of my methods could behave in 2 distinctly different ways. That significantly adds to the design cost of the application and reduces the reliability.
If neither reset nor something are virtual, you're screwed, and that's the end of the story. If something is virtual you could override it. However, if these necessary methods aren't virtual, then the class isn't intended to be extended (or implemented properly, if it was intended).
Edit:
You COULD try composition, e.g.
class Bar {
Foo f;
// foo's methods, etc, wrapped here
void something() {
f.reset();
reset();
}
};
But if you need the whole, implicit conversion, thing, you're still stuffed.
class Base {
public:
void foo() const {
std::cout << "foo const" << std::endl;
}
};
class Derived : public Base {
public:
void foo() {
std::cout << "foo"<< std::endl;
}
}
I want to make sure that foo() const is correctly hidden for Base. Yeah, this is a bad idea, and maybe I should make Base::foo() const a pure virtual to require Dervied::foo() to overridde correctly — but let's say that I cannot make Base::foo() const pure virtual. Is there a better way to make sure Base::foo() const is correctly hidden in Derived?
Edit: I want to make sure that in Derived I have correctly hidden the base implementation.
Simply by defining a member function foo in the derived class, you have hidden all of the foo functions in the base class.
You'll need to refine the question a little - are you concerned that the foo in the derived class is not a proper replacement for the foo in the base class? I'm having a hard time trying to determine what you're really asking for.
Edit: Based on your edit and additional comments, I think you have a misunderstanding of how hiding works in C++. In this case, it doesn't matter that one function is const and the other one isn't - once C++ finds a function foo in the derived class, it stops looking anywhere else! This is usually a huge trap for people. Consider the following:
class Base
{
void foo(double d)
{
cout << d;
}
};
class Derived : public Base
{
void foo(int i)
{
cout << i;
}
};
Derived obj;
obj.foo(123.456);
What do you think the output is? It's 123! And you probably got a compiler warning telling you the double value was going to be truncated. Even though the function signature that takes a double is obviously a better match, it's never considered - it has been hidden.
"void foo() const" and "void foo()" are two completely different functions as far as C++ is concerned. That's why you don't see the Derived's "foo" hiding the "foo" from the Base.
Are you sure you want to HIDE foo() from Base? If you want to exploit polymorphism you need to make the base version of foo() virtual. It does not have to be pure, though. Otherwise you get static binding - do you want that?
If you don't want to make it pure virtual and thereby force the implementation, you might just make the body of foo() in the Base class just immediately throw an exception. This serves the purpose of forcing any implementors and users to implement an override, or have it blow up when they try to use it.
I've seen this done before, and while it's a bit ugly, it very certainly works.
If I have understood your question properly, you are asking how to make sure that Derived classes override the method compulsorily, without making the method pure in Base class.
By making sure all of your derived classes to provide the implementation of the method, IMHO you are hinting that the method in Base class is really not used for any purpose. The objects must invoke any of the Derived class version of the method foo(). Hence, the method should be made pure virtual in my opinion. I don't think any other way to achieve this, I believe.
Also, note that in your example you have changed the signature of foo() in Base and Derived. This makes the Base class method to be invisible in Derived class. Unless you use using Base::foo, the method foo() will not be visible to Derived class.
In Base::foo(), you could do the following:
assert (dynamic_cast<const Derived*> (this) == NULL);
But it has three problems:
It requires a change in the Base class, which should be closed to modification.
It may be stronger than you need, since you may want to permit Base::foo() to be called from a Base object or explicitly.
It uses RTTI, which means a vtbl, which might be why you didn't want to user virtual functions to begin with.