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.
Related
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.
Let's say a virtual function is called on a derived class object (on the object normally or through pointer/reference) that overrides that function but none of its derived classes override it. Is it called "virtually" through v-pointer or as a normal function so all optimizations / inlining apply to it? Does the standard say anything about this?
class CBase{
public:
virtual void doSomething() = 0;
};
class CDerived1 : public CBase{
public:
void doSomething() override { /* do stuff */};
};
class CDerived2 : public CDerived1{
};
//...
CDerived1 derived1;
CDerived1* p_derived1 = &derived1;
p_derived1->doSomething();
Does the standard say anything about this?
No. Whether the call uses the dynamic dispatch mechanism or not is not observable behavior. And the standard only concerns itself with observable behavior.
How much compilers "devirtualize" virtual calls is ultimately implementation defined. If you just have T t; and you do t.whatever(), then you shouldn't use a compiler that cannot devirtualize that.
Inlining affects devirtualization as well. Given the T t declarations, if you pass a function a reference to this object, and it takes a T& parameter, calls into it can be devirtualized if that function gets inlined.
But if its a non-inlined instance of that function (say, a pointer to the function, perhaps through std::function or whatever), then devirtualization is much harder. See, the compiler doesn't see the whole program, so it cannot see if you have some class somewhere that inherits from T and overrides that method.
Only the linker, through whole program optimization, could possibly see all class definitions that inherit from it. And even then... maybe not. Because it is still technically possible for DLLs/SOs to inherit from classes. And the non-inlined function ought to be able to take those T&s and call their overridden methods.
So once you leave a chain of inlining where the object's dynamic type and virtual calls into it are both visible to the compiler, devirtualization becomes far more difficult if not impossible.
Let's say I have a fist class
class Walker {
public:
Walker();
virtual ~Walker();
virtual void Step();
};
Then a second one, deriving from the former
class Mecha : public Walker {
public:
Mecha();
virtual ~Mecha();
private:
virtual void Step();
};
Is that private modifier on Step() any useful? Mecha::Step() can still be called as Walker::Step(), isn't it? Shouldn't there be a warning as I'm trying to change the nature of the super-class through the definition of its sub-class?
Can a sub-class affect visibility of virtual methods?
Yes, they can change the visibility of the methods.
Is that private modifier on Step() useful?
Depends. It primarily affects the client of the code.
Increasing the visibility (e.g. going from protected to public) may be useful, but comes with a warning on it's use - the implementer of the base class interface desired that method to be internal to the hierarchy, making it external could break things... (possible implementations of the template method pattern come to mind).
Principally, changing the visibility doesn't affect the polymorphic nature of the virtual method - it still is overridden in the derived class. It does however affect the caller. Changing the method to private limits client code to calling the method from a pointer or reference to the base class and not the derived.
Mecha m;
//m.Step(); // fails to compile
Walker& w = m;
w.Step(); // still calls Mecha::Step()
Further, changing the method to protected would allow further sub-classes to call it.
No, making Step() private does not change the polymorphic behaviour. There's no warning since the language explicitly allows this. (But note that Java doesn't).
But it does prevent your being able to write Mecha::Step() explicitly unless you code that in a member function of Mecha.
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.
Sometimes I accidentally forget to call the superclass's method in C++ when I override a method.
Is there any way to help figure out when I'm overriding a method with, so that I don't forget to call the superclass's method? (Something like Java's #Override, except that C++ doesn't have annotations...)
One suggestion is the Non-Virtual Inferface Idiom. I.e., make your public methods non-virtual and have them call private or protected virtual methods that derived classes can override to implement their specific behavior.
If you don't have control over the base class, you could perhaps use an intermediate class:
class Foo // Don't control this one
{
public:
virtual void action();
};
class Bar : public Foo // Intermediate base class
{
public:
virtual void action()
{
doAction();
Foo::action();
}
protected:
virtual void doAction() = 0;
};
Derive your classes from Bar and override doAction() on each. You could even have doBeforeAction() and doAfterAction() if necessary.
With regards to Java's #Override, there is a direct equivalent in C++11, namely the override special identifier.
Sadly, neither #Override nor override solve the problem since: (a) they're optional; (b) the responsibility of calling the base class's method still rests with the programmer.
Furthermore, I don't know of any widely available method that would address the problem (it's quite tricky, esp. given that you don't necessarily want to call the base class's method -- how is the machine to know?).
Unfortunately Í'm not aware of a common mechanism to do this.
In C++ if you're needing to use the base class's functionality in addition to added child functionality you should look at the template method pattern. This way the common logic always lives in the base class and there's no way to forget to execute it, and you override in the child only the piece you need to change.