Understanding Inheritance and functions with different signatures - c++

Say I have a base class and a derived class.
class Base {
public:
void A(int x, int y) {do something}
void B() {
A(x,y);
do something;
}
};
class Derived : public Base {
void A() {do something else};
};
Derived derived1;
derived1.B();
The signatures of the functions are different, will the B call the derived A or the base A? Iif it will call the derived B, I guess it will dismiss the parameters?
what if the derived A needed different parameters rather than no parameters, would I have to copy B's entire code into the derived class just to change the way B calls A?

A function's code is always evaluated in the context of the class in which it is defined. This includes determining which function each expression calls. So inside Base::B(), the call A(x, y) is translated by the compiler as a call to Base::A. Even if you later call derived1.B(), it will call derived1 . Base::A (pseudo-syntax).
The only thing which changes this slightly is virtual functions. However, even with them, the rules are similar. Overload resolution (which is basically the process of matching a function name & signature to a call expression) is done in the context of the class where the containing function is defined. If the resolution leads to a virtual function being selected, the virtual call mechanism will then be invoked at runtime to call the appropriate override of that function.
Let's consider this example:
struct Base {
virtual void foo(int);
virtual void bar() { foo(0.0); }
};
struct Derived : Base {
virtual void foo(int);
virtual void foo(double);
};
Derived d;
d.bar();
Even in this example, calling d.bar() will call Derived::foo(int). That's because the call-to-signature matching was done in the context of Base, which only sees foo(int) and employs the implicit conversion from double to int.

Two reasons force Base::B to call Base::A not Derived::A
It's calling A with specific overload: A(int, int)
Base::A and Base::B are not virtual, so it calls Base::A. The code is not polymorphic.
The simplest example to show a how a virtual method works is:
class Base {
public:
virtual void A() {
// do job #1
}
};
class Derived : public Base {
public:
virtual void A() {
// do job #2
}
};
// ...
Derived derived1;
Base *base = &derived1;
base->A(); // <---- It calls `Derived::A()` and does job #2
But, if you write A in B with different parameter (overload it), you have to call it explicitly with actual arguments.

Related

How to defined a static interface in base class and make sure the interface must be implement in derived class?

It is very easy that we can make sure derived class must implement interface defined in base class.
That is pure virtual function.
For example:
class BaseClass
{
...
virtual void print()=0;
...
}
class DerivedClass :public BaseClass
{
// function must be implement, otherwise compiler will complain ...
void print()
{
}
};
Can we defined a static interface in base class and make sure the interface must be implement in derivate class?
I want something like this
class BaseClass
{
...
static void print(); // base class only define static interface
...
}
class DerivedClass :public BaseClass
{
// derived class must implement interface, otherwise compiler will complain ...
static void print()
{
}
};
I have no idea about this.
Thanks for your time.
It is not possible to make a virtual static function. For the simple reason that when calling a static function, you always know the class that defines that function in compile time. Unlike virtual functions, where you don't know the type of the object whose method you're calling.
For example:
class A
{
public:
virtual void f() {printf("A");}
};
class B : public A
{
virtual void f() override {printf("B");}
};
void g(A& a)
{
a.f();
}
int main()
{
B b;
g(b);
return 0;
}
In the above example, inside the function g, the correct function is invoked (B::f). Even though while compiling the function it is not known what the type of its argument is (it could be A or any class derived from A).
Without making f() virtual, you would have overloaded the method f, rather than overridden it. Which means that in the following example, the output would be "A", even though you might expect it to be "B":
class A
{
public:
void f() {printf("A");}
};
class B : public A
{
void f() {printf("B");}
};
void g(A& a)
{
a.f();
}
int main()
{
B b;
g(b);
return 0;
}
This may cause serious bugs, and it is suggested to never overload base class methods, and to always use the override keyword when overriding a virtual method to escape those bugs.
When making a static function, you can simply overload it, it would not create a compilation error. However, you probably never should overload it, because it may hide a bug that is very difficult to track (you are certain that B::f() is being called while actually A::f() is being called).
Furthermore, it is not possible to 'force' the derived class to implement a static interface, because there is no such thing as a static interface. Because you have no virtual static functions, you may not pass a reference or pointer to the interface that would implement this function.

Private overriden virtual functions in derived class

Is there any point to making virtual member functions, overridden from a base class private, if those are public in the base class?
struct base {
virtual void a();
};
struct derived : base {
// ...
private:
void a() override;
};
If you are forced to do a 2-phase construction on the implementation class (i.e. have an init() method as well as or instead of a constructor that has to be called (I know, but there are reasons), then this stops you calling any /other/ methods directly on the instance pointer before you pass it back as an interface pointer. Go the extra mile, make the inheritance private, and have your one public init function return the interface pointer!
Another reason is you just don't /need/ to write public: in a final implementation class declaration, so then by default everything is private. But why you would do that and use struct instead of class I don't know. Perhaps this was converted from class at some point due to a style war?
Looking at your design, I see one cannot call derived::a directly, but only through a base interface.
Is there any point? Consider that, once we have a derived instance, we can always up-cast to its base, so given
derived d;
while d.a() wouldn't compile, we can always do
base & b = d;
b.a(); //which actually calls derived::a
In other words: derived::a is not that private, after all, and I would discourage this design, which can be confusing to the user.
Things change if the members private in derived are private in base, as well: this time it is clear that they just cannot be called directly, outside base or derived.
Let's say we have a couple of functions, and want them to be called conditionally, according to a value passed as an argument to a third one:
struct base
{
void dosomething(bool x)
{
if(x)
{
do_this();
}
else
{
do_that();
}
}
private:
virtual void do_this(){}
virtual void do_that(){}
};
Thus a derived class could be like:
struct derived : base
{
private:
void do_this() override { }
void do_that() override { }
};
and no other class can call them, unless it extended base itself:
derived d;
d.dosomething(true); //will call do_this() in derived
d.dosomething(false); //will call do_that() in derived
d.do_that() //won't compile
Yes, if you inherit the base class as private. Otherwise, it is more of a weird explicit-like restriction - user has to has to make an explicit conversion to use the function - it is generally ill advised as few will be able to comprehend the author's intention.
If you want to restrict some functions from base class, make a private/protected inheritance and via using keyword declare which base-methods you want to be protected/public in the derived class.
The same reasoning as for non-virtual methods applies: If only the class itself is supposed to call it make it private.
Consider the template method pattern:
struct base {
void foo() { a() ; b(); }
virtual void a() = 0;
virtual void b() = 0;
};
struct derived : base {
private:
void a() override {}
void b() override {}
};
int main()
{
derived().foo();
}
Perhaps a and b should have been protected, but anyhow the derived can change accesibility and it requires some documentation so that derived knows how it is supposed to implement a and b.

Cast derived virtual override to base pure virtual member

I understand why you cannot simply cast a derived class member function pointer to base class member function pointer as explained here.
But, given this snippet:
struct base
{
virtual void foo() = 0;
};
struct derived : base
{
void foo() override {};
};
struct invoker
{
typedef void(base::*target)();
invoker(base* b, target t)
{
(b->*t)();
}
};
template<typename B, typename D>
void (B::*cast(void (D::*method)()))()
{
return static_cast<void(B::*)()>(method);
}
derived d;
invoker bad(&d, &derived::foo); //C2664
invoker good(&d, cast<base>(&derived::foo));
I wanted to ask is it possible to decorate the base function signature so that compiler understands it is a pure virtual method and and it will be implemented somewhere across the hierarchy (otherwise I could not construct an object of type B)? I understand why I can't do this with normal functions, but IMHO in case of a pure virtual function the compiler has a guarantee it will be implemented (in case it was not done I would get an error about the class B not about the cast).
There's no need to manipulate the type of &derived::foo. One can just use &base::foo instead.
Pointers to member functions respect virtuality. This call
base* pBase = new derived;
auto pFoo = &base::foo;
(pBase->*pFoo)();
will actually call derived::foo, exactly like a simple call pBase->foo() would.
Even if there's a guarantee that it's implemented, it might use additional data members declared only in derived. A possible solution is to use function pointers and pass this as the first parameter (this also shows you why you cannot do it via virtual).
Consider the following diamond hierarchy:
struct base {
virtual void foo() = 0;
};
struct D1 : public virtual base {
virtual void foo() override;
};
struct D2 : public virtual base {
virtual void foo() override;
};
struct Derived : public virtual D1, D2 {
virtual void foo() final;
};
Now consider a scenario where a upcast is allowed from Derived::* to base::* . Which function should be invoked? The compiler loses information about which of D1::foo, D2::foo or Derived::foo you wish to call since that information has been cast away. To avoid this sort of ambiguity such an upcast is disallowed.

passing derived object as base class reference parameter

This examples shows a derived class object being passed to a function which takes reference to base class as the parameter. Member function g(int) in the derived class hides the g(float) in the base class. I understand that and my question is not related to it.
class Base {
public:
virtual void g(float x) throw()
{
cout << "Base::g(float)\n";
}
};
class Derived : public Base {
public:
virtual void g(int x) throw() // Bad: Hides Base::g(float)
{
cout << "Derived::g(int)\n";
}
};
void sampleTwo(Base& b, Derived& d)
{
b.g(3.14f);
d.g(3.14f); // Bad: Converts 3.14 to 3 and calls Derived::g(int)
}
int main()
{
Derived d;
sampleTwo(d, d);
return 0;
}
Output is:
Base::g(float)
Derived::g(int)
My question is with the output "Base::g(float)". Since the object referenced by 'b' in sampleTwo() is derived object, shouldn't the dynamic binding call the g() method of the derived class (converting float to int) ?
g(int) and g(float) are two completely different methods. Derived::g(int) does not override Base::g(float). These methods are unrelated.
Since Derived does not override g(float), your expectations about b.g(3.14f) are unfounded. As expected, b.g(3.14f) should call Base::g(float).
If you override g(float) in Derived, then b.g(3.14f) will indeed call Derived::g(float).
Dynamic dispatch invokes the final overrider. Since Derived::g hides rather than overrides Base::g, the final overrider of Base::g in Derived is still Base::g.
g(float) and g(int) are different function members. If you want Derived to work, you have to use g(float) in both classes.
g() can be overloaded check out function overloading:
https://en.wikipedia.org/wiki/Function_overloading
Example (g(float) and g(int) in the same class and separate functions):
class Derived : public Base {
public:
void g(float x) throw();
void g(int x) throw();
};

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).