0

Shouldn't this be incorrect ? :

A* apb = (A*)&b; //a pointer to b

I would expect an error, or at least a warning.

Why is this not giving me any warning either in Visual C++ 2013 (v120) or in g++ (gcc 4.8.2) ?

#ifndef A_H
#define A_H

#include <stdio.h>

class A
{
public:
   A(){}
   virtual ~A(){}
   void print(){ printf("printA\n"); }
   virtual void printVirtual(){ printf("printVirtualA\n"); }
};

#endif // A_H

#ifndef B_H
#define B_H

#include "A.hpp"
class B : A
{
public:
   B(){}
   void print(){ printf("printB\n"); }
   virtual void printVirtual(){ printf("printVirtualB\n"); }
};

#endif //B_H

int main()
{
   A a;
   B b;
   A* apb = (A*)&b; //a pointer to b
   B* bpa = (B*)&a; //b pointer to a

   apb->print();         // printA
   apb->printVirtual();  // printVirtualB
   bpa->print();         // printB
   bpa->printVirtual();  // printVirtualA
   return 0;
}

Output:

printA
printVirtualB
printB
printVirtualA

I suspect it is because my classes are align in memory so there is a valid Vtable.

Is this an "implicit" dynamic_cast ?

From what I have learned it should not be correct to do this.

Scott
  • 383
  • 3
  • 10
  • You're forcing the compiler to do the cast with that C-style cast, so it's not complaining. Heck you could do `float* bad = (float*)&b;` and the compiler still wouldn't complain. But that doesn't make it valid. Neither of your casts are legal, I believe (`B` privately inherits from `A`, and `A` does not derive from `B`). – Cornstalks Nov 21 '14 at 05:29
  • What about the downcasting ? `B* bpa = (B*)&a; //b pointer to a` Is it because the classes have the same structure that this is executing correctly ? – Scott Nov 21 '14 at 17:33
  • 1
    It's actually undefined behavior and is illegal. However, it *appears* to work because `A` and `B` are very simple classes (they have no members, and those functions are just printing text and not doing anything complicated). Since `A` and `B` are so simple and are very close to being the same, they can kinda act as substitutes for each other. It's kinda like replacing a table leg with a leg from a stool: they're not the same, but close enough it'll likely work. However, try replacing an elephant leg with a stool's leg and things won't work out so well... – Cornstalks Nov 21 '14 at 17:38
  • @Cornstalks Thank you that was exactly the answer I was looking for. I still wonder why there is not warning at all about that. – Scott Nov 22 '14 at 18:02

3 Answers3

1

this is exactly what vtables are for. non-virtual functions are called matching the type of the container, and virtual functions are called matching the type of the pointed object.

A* apb = (A*) &b;

.... is perfectly fine code, and is a classic example of virtual polymorphism.

Jules G.M.
  • 3,624
  • 1
  • 21
  • 35
  • 2
    However, `B* bpa = (B*)&a;` is *not* perfectly fine code... (also: none of these functions are static). Also, doesn't private inheritance ruin the legality of this code? – Cornstalks Nov 21 '14 at 05:26
  • indeed. I called a non virtual funciton static, because it gets called in a static fashion, not as per the c++ keyword. but you are right. – Jules G.M. Nov 21 '14 at 05:30
  • That's kinda sorta true, but not totally. The function gets called with a `this` pointer (it just happens to not use it), which means its calling conventions aren't quite like `static` functions. – Cornstalks Nov 21 '14 at 05:32
  • by static I meant that the call address is not determined at runtime, but at compile time, as opposed to virtual/dynamically at runtime with the vtable – Jules G.M. Nov 21 '14 at 05:34
0
A* apb = (A*)&b;

Is perfectly OK to initialize a base class pointer from a derived class (supposed b is of type B as you're showing). You don't even need the cast operation

A* apb = &b;

The void print() member functions aren't marked virtual, thus the member functions are called on the actual instance you have at hand.

πάντα ῥεῖ
  • 1
  • 13
  • 116
  • 190
  • 1
    I don't think it is perfectly okay. Notice that he's privately inheriting, not publicly inheriting. – Cornstalks Nov 21 '14 at 05:29
  • @Cornstalks Good spot. Yes, forcing the conversion may hide an error given for `A* apb = &b;`. Though inheriting publicly should fix this, and there's no real change in the behavior. The point is, the `print()` functions aren't `virtual`. – πάντα ῥεῖ Nov 21 '14 at 05:33
0
A* apb = (A*) &b;

This is perfectly alright. Base pointer pointing to derieved object. This scheme is mostly followed by abstract classes (or interfaces) to anable polymorphism

Ali Kazmi
  • 1,460
  • 9
  • 22