Virtual functions only called when using an indirection — Classical early binding issue? - c++

I have three different implementations of an interface (solving systems of equations). The old interface essentially was void foo(int *f) within a class. Now I want to generalize this to a case where I solve N systems at the same time. For this I want to have the interface void foo(int *f[N]).
In the codebase there is an abstract class defining the interface, then three classes derive from that class. I would like to add my generalization without breaking existing code. Therefore I thought of adding the new interface and have the old interface delegate to the new one. This is my compressed version:
#include <iostream>
struct AbstractClass {
/// Old interface, needs to be retained.
virtual void foo(int *f) {
std::cout << "AbstractClass::foo(int *f)\n";
int *a[2] = {f, nullptr};
foo(a);
}
/// New interface.
virtual void foo(int *f[2]) {
std::cout << "AbstractClass::foo(int *f[2])\n";
}
};
struct Derived : public AbstractClass {
/// New interface.
void foo(int *f[2]) override {
std::cout << "Derived::foo(int *f[2])\n";
}
};
int main(int argc, char **argv) {
// Code using the old interface.
Derived d;
int *a;
d.foo(a);
}
Work with the code.
My hope is that the call of d.foo(a) would go to the inherited Derived::foo(int *f) and from there to Derived::foo(int *f[2]). However, g++ 6.3 gives me the following (in C++11 mode):
inheritance-test.cpp: In function 'int main(int, char**)':
inheritance-test.cpp:31:12: error: no matching function for call to 'Derived::foo(int*&)'
d.foo(a);
^
inheritance-test.cpp:21:10: note: candidate: virtual void Derived::foo(int**)
void foo(int *f[2]) override {
^~~
inheritance-test.cpp:21:10: note: no known conversion for argument 1 from 'int*' to 'int**'
It looks like the derived objects do not really have inherited the methods that I want.
Using runtime polymorphism with a pointer to the base class does work, though:
AbstractClass *pd = new Derived();
int *a = nullptr;
pd->foo(a);
delete pd;
I do not really understand why it does not work without the pointer. The vtable is not used with automatic storage because the function calls are bound at compile time (early binding)?
This is getting me a bit closer to the solution, but I would still have to touch all the code which uses this library. However, that is not really an option, the old stuff has to keep working.
What can I do about that (other than duplicating all code)? Would it be sufficient to have this delegation copied into each derived class?

There is something known as name hiding in C++. Basically, when you override a member function in a derived class, it hides all other overloads found in the base class.
That is why below fails:
Derived d;
int *a;
d.foo(a);
And below works:
AbstractClass *pd = new Derived();
int *a = nullptr;
pd->foo(a);
Because the overload of foo that takes a pointer is in AbstractClass but is hidden in Derived.
You can make those overloads visible with a using.
struct Derived : public AbstractClass {
using AbstractClass::foo;
void foo(int *f[2]) override {
std::cout << "Derived::foo(int *f[2])\n";
}
};
Demo

Related

Passing member method of derived class as base class method pointer

Can I pass the method as a pointer to some function that accepts the base class method pointer?
Like here, function tryit accepts two parameters with class Object. There should be polymorphism, but the compiler throws an error.
#include <iostream>
using namespace std;
class Object {
};
class Derived : public Object
{
private:
public:
void printit() {
cout << "Ok" << endl;
}
};
void tryit(Object* obj, void (Object::*fn)() ) {
(obj->*fn)();
}
int main() {
Derived d;
tryit(&d, &Derived::printit);
}
Compiler says this:
main.cc: In function ‘int main()’:
main.cc:31:15: error: cannot convert ‘void (Derived::*)()’ to ‘void (Object::*)()’
31 | tryit(&d, &Derived::printit);
| ^~~~~~~~~~~~~~~~~
| |
| void (Derived::*)()
main.cc:24:25: note: initializing argument 2 of ‘void tryit(Object*, void (Object::*)())’
24 | void tryit(Object* obj, void (Object::*fn)() ) {
| ^~~~~~~~~~~~~~~~~~~~
I don't want to use virtual methods in Object class, because I want to be able to call function with various names.
This works:
typedef void (Object::*memfn)();
tryit(&d, (memfn) &Derived::printit);
But why this is not converted implicitly, why do I need to cast it manually?
Unfortunately, polymorphism doesn't work this way. Member-pointers of derived classes are not implicitly convertible to member-pointers of parent classes. Only pointers (and references) to derived class objects are implicitly convertible to pointers to parent class objects.
You can cast your pointer, and make compiler happy:
int main() {
Derived d;
tryit(&d, static_cast<void (Object::*)()>(&Derived::printit));
}
Thanks to #StoryTeller-UnslanderMonica for digging, there seems to be an explicit blessing in Standard:
https://timsong-cpp.github.io/cppwp/n4868/expr.static.cast#12
Using virtual is the legal and safe way to handle this for polymorphic types. Your claim that you don't want to use virtual because you "want to be able to call function with various names" makes no sense.
But, if you really don't want to use virtual then consider making tryit() a template function instead, eg:
template<typename T>
void tryit(T* obj, void (T::*fn)() ) {
(obj->*fn)();
}
int main() {
Derived d;
tryit(&d, &Derived::printit);
}
Alternatively:
template<typename Callable>
void tryit(Callable fn) {
fn();
}
int main() {
Derived d;
tryit([&](){ d.printit(); });
}
Or, you can use std::function without a template, eg:
void tryit(std::function<void()> fn) {
fn();
}
int main() {
Derived d;
tryit([&](){ d.printit(); });
}
But why this is not converted implicitly, why do I need to cast it manually?
Because it's one of those conversions where you have to tell the compiler you posses extra knowledge that guarantees it's safe. Take object pointers for instance:
struct A { int x; };
struct B : A { char c; };
A *pa = new B();
auto pb = static_cast<B*>(pa);
Converting a B* to an A* is implicit. It's an unambiguous base class. The compiler knows there is an A object in that B and can just go ahead with it. But the converse is not true, you must cast it (employing your extra knowledge) to let it know that that A* is really pointing at a B*.
Pointers to members are the same in a way.
int B::* pmb = &A::x;
auto pma = static_cast<char A::*>(&B::c);
pa->*pma = 'c';
Obtaining a pointer to a member of B from a pointer to a member of A is an implicit conversion. The same knowledge about B containing an A (and therefore the member x) is available to the compiler. But it cannot assume the converse willy-nilly. What if the object pointer pa is not really pointing at a B? Accessing that "member of B" would be disastrous then.
By the same reasoning as before, you need a cast to let the compiler know you have extra knowledge about the actual derived object type.

Explicitly stop late binding

If we create an object pointer to base class class which points to its child class object then we use virtual key word for late binding
So.,in case of late binding,, our code goes like this :-
#include<iostream>
using namespace std;
struct A{
virtual void print() {
cout<<"function1";
}
};
struct B : public A{
void print(){
cout<<"function2";
}
};
struct C : public B{
void print(){
cout<<"function3";
}
};
int main(){
A* a = new C();
A* p = new B();
a->print();
p->print();
}
Now my question is : when we use virtual keyword in base class, all the functions of derived classes created in base class will become virtual.
In multilevel inheritance, is there any way so that we can stop the function of class c from being virtual??
Any way to break this chain of virtual functions ?
Sorry for any mistakes in question but i tried my best.. ☺️☺️
It is not possible to make a function that is already virtual be not virtual in a child class.
Virtuality is a property of the top-level base class, not the child classes. Once a method has been marked as virtual, and pointer to that class must use dynamic dispatch for that function when calling because the pointer could be pointing to a child class that has overridden the behaviour.
Consider this code:
A a;
B b;
C c;
A * ap = &a;
A * bp = &b;
A * cp = &c;
ap->print(); // 'function1'
bp->print(); // 'function2'
cp->print(); // 'function3'
Here, the calls to print cannot tell which function to call at compile time, they absolutely must use dynamic dispatch.
However, you can make C::print behave like A::print
struct C : public B {
void print() {
A::print();
}
};
Which results in:
ap->print(); // 'function1'
bp->print(); // 'function2'
cp->print(); // 'function1'
And if the behaviour of A::print() changes, C::print() mirrors those changes.
This will still be overridable though, unless you use the final keyword as outlined below.
Original answer:
I believe you are looking for the final specifier.
It's only available as of C++11 though.
To quote en.cppreference's page about the final specifier:
When used in a virtual function declaration or definition, final
ensures that the function is virtual and specifies that it may not be
overridden by derived classes. The program is ill-formed (a
compile-time error is generated) otherwise.
And a variation of the example they give, demonstrating the solution to your problem:
struct A
{
virtual void foo();
};
struct B : A
{
void foo() final; // B::foo is overridden and it is the final override
};
struct C : B
{
void foo() override; // Error: foo cannot be overridden as it's final in B
};

error: 'A' is an inaccessible base of 'B'

I've a code as follows -
#include <iostream>
#include <string>
class A{
int a;
public: virtual void sayHello(){ std::cout << "Hello\n"; }
};
class B : private A{
std::string name;
public:
B(std::string _n): name(_n){}
void sayName(){std::cout << name << "says hello\n";}
void sayHello(){sayName();}
};
int main() {
A *ptr = new B("c++");
ptr->sayHello();
return 0;
}
which produces the following compiler output -
Error:
prog.cpp: In function 'int main()':
prog.cpp:20:22: error: 'A' is an inaccessible base of 'B'
A *ptr = new B("c++");
^
As previously answered - here, here & here, I know how to solve this issue. By using public inheritence instead of private or protected.
But if I really really want to hide some interface behind the base class, isn't there some other way to do this? Or is it impossible to do so according to c++ lang specification.
If you want polymorphic pointer conversion to work outside the class, then the inheritance must be public. There is no way to work around that.
You could add a member function that does the polymorphic pointer conversion within the class:
class B : private A{
// ...
public:
A* getA() {
return this;
}
};
Which allows you to do this, while still allowing private inheritance:
B* b_ptr = new B("c++");
A* ptr = b_ptr->getA();
// ptr = b_ptr; // only allowed in member functions
I haven't encountered a real world design where this trick would be useful, but suit yourself.
PS. Remember that you should destroy objects that you create. Also do realize that delete ptr has undefined behaviour, unless ~A is virtual.
Even though I find it quite strange to hide the base class and want to cast B to A, you can use for that the operator A*().
It follows a minimal, working example:
#include <iostream>
#include <string>
class A{
int a;
public:
virtual void sayHello(){ std::cout << "Hello\n"; }
};
class B : private A{
std::string name;
public:
B(std::string _n): name(_n){}
operator A*() { return this; }
void sayName(){std::cout << name << "says hello\n";}
void sayHello(){sayName();}
};
Now you can use it as:
int main() {
A *ptr = *(new B("c++"));
ptr->sayHello();
return 0;
}
Or even better:
int main() {
B b{"c++"};
A *ptr = b;
ptr->sayHello();
return 0;
}
Adding the cast to A& is as easy as adding the member method operator A&() defined as return *this;.
There is an unsightly way around this: C style casts. C style casts can cast to inaccessible base classes. This is the one and only case where C style casts can do something that C++ casts can't. From cppreference, when a C style cast (T) foo attempts to perform static_cast<T>(foo), it can do slightly more than just a static_cast:
[P]ointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible (that is, this cast ignores the private inheritance specifier).
Emphasis added
Thus, you can do this:
int main() {
A *ptr = (A *) new B("c++");
ptr->sayHello();
return 0;
}
This is ugly, and it comes with all the disadvantages of casting and especially of C style casts. But it does work, and it is allowed.
Live on Wandbox
When you want to hide that A is a base of B this is valid.
But you assignment
A *ptr = new B("c++");
breaks this hiding, because you use an A*. So c++ generates an error because the dependency is hidden. You can do
B *ptr = new B("c++");
though.

Function overriding in C++ works without 'virtual'

I have a class that contains some functions (none are virtual) and 2 more classes publicly inherit that class. In both the sub classes I override the same function of the base class.
After creating objects of all three classes in main (located at the same file), I call the original function with the baseclass object and the overridden functions with the derivedclass objects.
I was expecting all 3 function calls to run the original function from the base class (since I didn't use 'virtual' anywhere in the code), but I actually get each version of that function working according to the class in which it was defined (3 different versions).
I have the classes Base & Derived as follows:
struct Base
{
void foo();
};
struct Derived : Base
{
void foo();
};
in main:
int main()
{
Derived d;
d.foo();
}
I thought d.foo() should run Base::foo() if not using 'virtual'.
This is not "overriding"... and it doesn't need to be.
struct Base
{
void foo();
};
struct Derived : Base
{
void foo();
};
int main()
{
Derived d;
d.foo();
}
If I understand you correctly, then you were expecting this to execute Base::foo(), because the functions are not virtual and therefore one does not override the other.
But, here, you do not need virtual dispatch: the rules of inheritance simply state that you'll get the right function for the type of the object you run it on.
When you need virtual dispatch/overriding is a slightly different case: it's when you use indirection:
int main()
{
Base* ptr = new Derived();
ptr->foo();
delete ptr;
}
In the above snippet, the result will be that Base::foo() is called, because the expression ptr->foo() doesn't know that *ptr is really a Derived. All it knows is that ptr is a Base*.
This is where adding virtual (and, in doing so, making the one function override the other) makes magic happen.
You cannot override something that isn't virtual. Non-virtual member functions are dispatched statically based on the type of the instance object.
You could cheat by "overriding" a function by making it an inline function calling something indirectly. Something like (in C++03)
class Foo;
typedef int foo_sig_t (Foo&, std::string&);
class Foo {
foo_sig_t *funptr;
public:
int do_fun(std::string&s) { return funptr(*this,s); }
Foo (foo_sig_t* fun): funptr(fun) {};
~Foo () { funptr= NULL; };
// etc
};
class Bar : public Foo {
static int barfun(Bar&, std::string& s) {
std::cout << s << std::endl;
return (int) s.size();
};
public:
Bar () : Foo(reinterpret_cast<foo_sig_t*>)(&barfun)) {};
// etc...
};
and later:
Bar b;
int x=b.do_fun("hello");
Officially this is not overloading a virtual function, but it looks very close to one. However, in my above Foo example each Foo instance has its own funptr, which is not necessarily shared by a class. But all Bar instances share the same funptr pointing to the same barfun.
BTW, using C++11 lambda anonymous functions (internally implemented as closures), that would be simpler and shorter.
Of course, virtual functions are in generally in fact implemented by a similar mechanism: objects (with some virtual stuff) implicitly start with a hidden field (perhaps "named" _vptr) giving the vtable (or virtual method table).

C++ member function virtual override and overload at the same time

If I have a code like this:
struct A {
virtual void f(int) {}
virtual void f(void*) {}
};
struct B : public A {
void f(int) {}
};
struct C : public B {
void f(void*) {}
};
int main() {
C c;
c.f(1);
return 0;
}
I get an error that says that I am trying to do an invalid conversion from int to void*. Why can't compiler figure out that he has to call B::f, since both functions are declared as virtual?
After reading jalf's answer I went and reduced it even further. This one does not work as well. Not very intuitive.
struct A {
virtual void f(int) {}
};
struct B : public A {
void f(void*) {}
};
int main() {
B b;
b.f(1);
return 0;
}
The short answer is "because that's how overload resolution works in C++".
The compiler searches for functions F inside the C class, and if it finds any, it stops the search, and tries to pick a candidate among those. It only looks inside base classes if no matching functions were found in the derived class.
However, you can explicitly introduce the base class functions into the derived class' namespace:
struct C : public B {
void f(void*) {}
using B::f; // Add B's f function to C's namespace, allowing it to participate in overload resolution
};
Or you could do this:
void main()
{
A *a = new C();
a->f(1); //This will call f(int) from B(Polymorphism)
}
Well I think first of all you did not understand what virtual mechanism or polymorhism. When the polymorphism is achieved only by using object pointers. I think you are new to c++. Without using object pointers then there is no meaning of polymorphism or virtual keyword use base class pointer and assign the desired derived class objects to it. Then call and try it.