Here's a piece of code I had written to see the behaviour during downcasting.
#include <iostream>
using namespace std;
class base {
public :
void function()
{
cout << "\nInside class Base";
}
};
class derived : public base {
public :
void function()
{
cout << "\nInside class Derived.";
}
};
int main()
{
base * b1 = new base();
base * b2 = new derived();
derived * b3 = (derived*)b1 ;
b1 -> function();
b2 -> function();
b3 -> function(); // print statement 3
static_cast<derived*>(b2) -> function();
static_cast<derived*>(b1) -> function(); // print statement 5
return 0;
}
The output is as follows .
Inside class Base
Inside class Base
Inside class Derived.
Inside class Derived.
Inside class Derived.
I feel print statement 3 and print statement 5 should have displayed "Inside class base" .
Can someone please explain what I might be missing here?
Both are cases of undefined behavior. Casting b1 to derived* is not valid.
However, if you said base* b1 = new derived(), you would have the same behavior. Since neither function is marked virtual, then it only checks objects type at compile time.
So the first case would print "Inside class Base", even though its actually a derived pointer.
You need to define base method void function() as virtual:
virtual void function()
{
cout << "\nInside class Base";
}
and resulting output is:
Inside class Base
Inside class Derived.
Inside class Base
Inside class Derived.
Inside class Base
In OP, 5th case may not be an undefined behaviour as stated in the reference1 and inline member function memory is not stored like data members as stated here insuring that after static cast to derived type, derived member function is called:
The inverse of any standard conversion sequence (Clause 4) not
containing an lvalue-to-rvalue (4.1), array-to- pointer (4.2),
function-to-pointer (4.3), null pointer (4.10), null member pointer
(4.11), or boolean (4.12) conversion, can be performed explicitly
using static_cast.
1 Working Draft, Standard for Programming Language C++, 5.2.9 Static Cast - 7
The functions are dispatched at compilation time, based solely on the static type, as they are not virtual.
Static type of b3 in print statement is Derived *, hence 'Inside class Derived'. Print statement 5 casts Base * to Derived *, hence the same printout.
Add virtual to function() definition in Base and check again to see what happens.
That's the expected behavior.
Non virtual methods are called by the object's type at compile time.
You used a static cast, so the compiler treats it as "Derived" class.
If you'd declare the method as virtual then it will create a virtual look up table for the function, and call the method according to the actual run-time type.
Related
This has been provided in my official notes but I spotted an error. Before I take it up to my instructor, I just thought of confirming it here with all my blood brothers- you guys.
#include <iostream.h>
class Base {
public:
virtual void display() { cout << "Base class" << endl; }
};
class Derived: public Base {
// Nothing here
};
void main()
{
Base * ptr;
// Calls Base::display ( )
ptr = new Base ;
ptr ->display();
delete ptr ;
// Calls Base::display ( ) again
ptr = new Derived ;
ptr ->display();
delete ptr ;
}
The output is:
Base class
Base class
I think the problem is in the very last line of the main function. I mean, since the destructor is not virtual, I don't think you can delete a dynamically allocated instance of the derived class type using the pointer of the base class type. What do you think?
I mean, since the destructor is not virtual, I don't think you can delete a dynamically allocated instance of the derived class type using the pointer of the base class type. What do you think?
You can see here and here that this is undefined behavior.
If the base class has no virtual destructor the behavior of such code is simply undefined.
From the C++ standard:
5.3.5 Delete
3 In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.
When a function is defined as virtual then the compiler will call the function using a pointer to the base using dynamic binding, i.e. the call to the actual function will go through the class vTable to find the relevant implementation of the function. If a function is not defined as virtual then the code generated by the compiler will use static binding, i.e. the compiler will simply call the function it knows. In other words, if you call a non-virtual function on the base class pointer which points to a derived class then the compiler will generate code for calling the base class implementation.
Now, destructor behavior is just a private case of the general behavior described above. As in the absence of a destructor implementation the compiler will generate a default non-virtual destructor for you, the destruction of an object using a base class pointer will just call the base class destructor. You can reproduce this behavior it easily by explicitly defining the non-virtual destructors for both base and derived classes and use the debugger to see that the base class version is the one being called.
In the artificial example below, if I static_cast to the base class, when I call the setSnapshot() function it still calls the actual object setSnapshot(). This is what I want to happen. My question is can I always rely on this to work?
In code I am working on, we have this class hierarchy and in the b class there are macros used which static cast to the b type. This is to downcast from a base type so that specialised function in b can be called.
#include <iostream>
class a {
};
class b: public a {
public:
virtual void setSnapshot() { std::cout << "setting b snapshot\n"; }
};
class c : public b {
public:
virtual void setSnapshot() { std::cout << "setting c snapshot\n"; }
};
int main() {
a* o = new c;
//specifically casting to b
static_cast<b*>(o)->setSnapshot(); //prints setting c snapshot - what I want to happen
delete o;
return 0;
}
The title suggests that you're misunderstanding what the case does. new c creates an object of type c, and it will remain a c until it's destructed.
If you were to cast it to an a, you'd create a copy. But yu're only casting pointers. That doesn't affect the original object. That's still a c, and that's why you end up calling c::setSnapshot().
As long as a function is virtual in the statically known type a call of it will go to the override that is most derived.
For single inheritance this can be understood as a search for an implementation up the base class chain, starting in the most derived class.
In practice, for C++, the dynamic search is not done, and the effect of the search is instead implemented as a simple table lookup.
I find when writing functions (that use function overloading) that accept either a main class or subclass argument, that often implicit upcasting will occur (the subclass is upcasted as the main class and the main class function called). I don't want this implicit upcasting to occur as it means subtle bugs sneak in and cause problems later on down the line.
I have searched on google for information on this, but there is little coherent information I can make use of and only indirect references to it.
How do I disable, stop or prevent implicit upcasting (and even downcasting) from occurring?
(I can't supply any example code as this is a general problem that occurs from time to time).
No, this isn't to do with methods (I would have specified methods) but functions.
No example code, but pseudo idea:
void Function(BaseClass &A);
void Function(SubclassClass &B);
Function(ASubclass); //Implicit upcasting occurs, calls BaseClass instead
The above situation won't happen conventionally (say that the SubclassClass function gets knocked out/erased), but Subclass will be upcast to the BaseClass for use with the BaseClass function, instead of, say, reporting an error or generating a warning - either would be helpful as I don't want implicit upcasting to occur.
Please don't confuse upcasting with non-virtual method calls.
class Base
{
};
class Derived1:public Base
{
};
class Derived2:private Base
{
};
void doSomething(Base *ptr)
{
}
int main()
{
Derived1 *ptr1 = new Derived1;
Derived2 *ptr2 = new Derived2;
doSomething(ptr1); //works fine
doSomething(ptr2); //Gives error
return 0;
};
Upcasting:
A Base class pointer can always point to a derived class object as long as the derived class is publically derived from the Base class. Eg: First Function Call.
This upcasting happens implicitly.
If the derivation is private this upcasting does not happen implicitly and compiler will issue an error.
Though, using private inheritance is not the way to achieve this behavior. You should use private inheritance if it suits your design and it will implicitly gaurantee you that upcasting never happens implicitly.
The "up-casting" you are talking about is normal. The symptoms you are describing sound like you are overloading a non-virtual parents member function.
For example
#include <iostream>
using namespace std;
struct A
{
void sayHello() {cout << "hello from A" << endl;}
};
struct B : public A
{
void sayHello() {cout << "hello from B" << endl;}
};
void hello(A& a)
{
a.sayHello();
}
int main()
{
A a;
B b;
hello(a);
hello(b);
}
will produce
hello from A
hello from A
but if you add the virual to A::sayHello everything works as you would expect
struct A
{
virtual void sayHello() {cout << "hello from A" << endl;}
};
I'm not 100% sure what's going on, but if base class methods are being called when you supply a derived-class object to a method with a base-class parameter type, then either a) you didn't override the base-class method in your derived class, or more likely b) you forget the 'virtual' keyword in your base-class declaration. Otherwise the derived-class method will be called as expected.
#Als your example wont work if derivation is in protected mode.Implicit upcasting is allowed within the derived class only (within methods of the derived class) because protected members can only be accessed inside the class that derives or base class.
C++ type change during deletion
I've read that when you construct a derived type, the type changes depending on which constructor is being called. So, if you create a derived object and call a virtual function using a base pointer, normally it would map to the implementation in the derived class. If you called the virtual function in the base class constructor though, it would use the base class implementation as the type of the object is technically that of the base class while in that function. For example (makeshift code, sorry if it doesn't compile):
class Base {
Base()
{
std::cerr << "Base Constructor.";
func();
}
virtual void func() {
std::cerr << "Func base called." << std::endl;
}
};
class Derived : public Base {
Derived()
{
std::cerr << "Derived Constructor.";
func();
}
void func() {
std::cerr << "Func derived called." << std::endl;
}
};
int main() {
Derived* d = new Derived;
delete d;
}
Should output:
Base Constructor.
Func base called.
Derived Constructor.
Func derived called.
First of all, is this always true or is it implementation dependent?
If I used RTTI and typeinfo, would the type printed in the base actually be that of the base, or is this more of an unwritten rule sort of situation?
Is it dangerous to call virtual functions from constructors with this in mind, or is it safe as long as you know what you're doing?
To keep it short and simple, you can have a Rule:
The virtual mechanism is disabled in Constructors and Destructors
A virtual function call in Base class will always call the base class version of the function, the same in derived class results in call to the Derived class version of the function.
First of all, is this always true or is it implementation dependent?
Yes this is always true. This is not implementation-dependent.
If I used RTTI and typeinfo, would the type printed in the base actually be that of the base?
Yes it would be of Base; Derived object doesn't even exist while you are in Base class constructor.
Is it dangerous to call virtual functions from constructors with this in mind, or is it safe as long as you know what you're doing?
No it is not dangerous to call virtual functions from constructor as long as you understand the semantics behind it.
This C++ FAQ should be a good read for you.
It's well-defined.
[n3290: 12.7/4]: Member functions, including virtual functions
(10.3), can be called during construction or destruction (12.6.2).
When a virtual function is called directly or indirectly from a
constructor or from a destructor, including during the construction or
destruction of the class’s non-static data members, and the object to
which the call applies is the object (call it x) under construction or
destruction, the function called is the final overrider in the
constructor’s or destructor’s class and not one overriding it in a
more-derived class. If the virtual function call uses an explicit
class member access (5.2.5) and the object expression refers to the
complete object of x or one of that object’s base class subobjects but
not x or one of its base class subobjects, the behavior is undefined.
There is an excellent article from Scott Meyers. It is from his book Effective C++.
The article can be found at:
Never Call Virtual Functions during Construction or Destruction
It also discusses an alternative implementation.
Recently I had a similar problem which I solved this way:
class EthernetFrame
{
protected:
/** ctor to be called from derived classes */
EthernetFrame(unsigned inPayloadLength)
{
calculatePadBytes(inPayloadLength);
}
private:
/** calculates needed required PadBytes for Frames < 64B
* #param inPayloadLength we need to know the length of the actual L3 frame
*/
void calculatePadBytes(unsigned inPayloadLength);
};
class IPv4Frame : public EthernetFrame
{
public:
/** create empty IPv4 packet */
IPv4Frame() :
EthernetFrame(cIPv4_MINIMUM_LENGTH)
{};
// IPv4 header + trailer in bytes
unsigned cIPv4_MINIMUM_LENGTH;
protected:
/** ctor to be called from derived classes */
IPv4Frame(unsigned inPayloadLength) :
EthernetFrame(cIPv4_MINIMUM_LENGTH+inPayloadLength)
{};
};
I would like to know how c++ ensures the concept layout in memory of these classes to support inheritance.
for example:
class Base1
{
public:
void function1(){cout<<"Base1"};
};
class Base2
{
public:
void function2(){cout<<"Base2"};
};
class MDerived: Base1,Base2
{
public:
void function1(){cout<<"MDerived"};
};
void function(Base1 *b1)
{
b1->function1();
}
So when I pass function an object of derived type the function should offset into the base1 class function and call it. How does C++ ensure such a layout.
When a MDerived* needs to be converted to a Base1*, the compiler adjusts the pointer to point to the correct memory address, where the members of this base class are located. This means that a MDerived* that is cast to a Base1* might point to a different memory address than the original MDerived* (depending on the memory layout of the derived class).
The compiler can do this because it knows the memory layout of all the classes, and when a cast occurs it can add code that adjusts the address of the pointer.
For example this might print different addresses:
int main() {
MDerived *d = new MDerived;
std::cout << "derived: " << d << std::endl;
std::cout << "base1: " << (base1*)d << std::endl;
std::cout << "base2: " << (base2*)d << std::endl;
}
In your example such adjustments might not be necessary since the classes don't contain any member variables that would use any memory in the sub-objects representing the base classes. If you have a pointer pointing to "nothing" (no member variables), it doesn't really matter if that nothing is called Base1 or Base2 or MDerived.
The non-virtual methods of the classes are not stored with each object, they are stored only once. The compiler then statically, at compile time, uses those global addresses when a member function is called, according to the type of the variable used.
The layout of a class in memory includes its members and base class subobjects (§10/2). Members are also subobjects. A pointer to a base subobject is a pointer to an object (but not a most-derived object).
When you convert an MDerived * to a Base2 *, the compiler looks up the offset of the Base2 object inside the MDerived object and uses it to generate this for the inherited method.
I think you're asking why, when you call b1->function(), does Base1::function1() fire?
If so, then the reason is because b1 is a Base1 pointer, not a MDerived pointer. The object it points to may in fact "be" an MDerived object, but function(Base1*) has no way of knowing this, so it calls the only thing it does know -- Base1::function1().
Now, if you had marked the base class function as virtual, things change:
#include <iostream>
#include <string>
using namespace std;
class Base1
{
public: virtual void function1() { cout<<"Base1"; }
};
class Base2
{
public: void function2(){cout<<"Base2";}
};
class MDerived: public Base1, public Base2
{
public: void function1(){cout<<"MDerived";}
};
void function(Base1 *b1)
{
b1->function1();
}
int main()
{
MDerived d;
function(&d);
}
The output of the program is:
"MDerived"
void function(Base1 *b1) still doesn't know that the object being pointed to is actually an MDerived, but now it doesn't have to. WHen you call virtual functions through a base class pointer, you get polymorphic behavior. Which in this case means MDerived::function1() is called because that is the most-derived type available.
Few things in your code
The multiple inheritance should be public, else the compiler will complain that there is no access to the base classes
No ; at the end of the cout statements
Did not include the <iostream> (ok may be I am being too pedantic)
To answer your question - the compiler knows that it is the base class because the type of the argument that the function is taking is Base1. The compiler converts the type of the passed data (assuming you passed a derived object, does object slicing) and then calls the function1() on it (which is a simple offset from the base pointer calculation).