I asked a question an hour or two ago that is similar but this is fundamentally different to me. After this I should be good.
class base
{
private:
string tame;
public:
void kaz(){}
virtual ~base() {}
void print() const
{
cout << tame << endl;
}
};
class derived: public base
{
private:
string taok;
public:
std::string name_;
explicit derived( const std::string& n ) : name_( n ) {}
derived(){}
void blah(){taok = "ok";}
void print() const
{
std::cout << "derived: " << name_ << std::endl;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
base b;
derived d;
base * c = &b;
derived * e = (derived *)&b;
e->kaz();
system("pause");
return 0;
}
I know downcasting in in this example is not good practice but I'm just using it as an example. So when I now am pointing to a base object from a derived pointer, I don't get why I am still able to do certain operations only belonging to the base class.
For example, the base class's interface has a Kaz() method but the derived method does not. When I downcast, why does the compiler not yell at me for doing this even though Kaz() is not part of the derived class's interface?
Why is the compiler not complaining for using members of the base class when I am using a derived pointer?
Why does the compiler yell at me only when I access a member from the base class interface from within a method but not directly?
For example:
I can't do this:
e->print() //Program crashes
But I can do this:
e->tame = "Blah";
cout << e->tame << endl;
First you should use dynamic_cast<derived*>(&b) instead of the C-style cast.
Then you should declare the print() method as virtual if you want to override the method in the subclass.
The line e->tame = "Blah"; should cause the compiler to issue an error if not used inside of a class method because it is declared private.
Last the kaz() method can be called on the derived object because the subclass contains all methods from the base class plus the ones defined in the derived class.
The derived class inherits all the members of the base class, so kaz() exists also for derived objects. If you call kaz() on a derived object, simply the method that was inherited from base is called. If you access the inherited members from within a method or directly doesn't matter.
The problem with e is that it is really pointing to a base object, not a derived. With the cast e = (derived *)&b you tell the compiler "I know it doesn't look like it, but this really is a derived *, believe me!". And the compiler believes you, since you are the master. But you lied and &b was actually not a derived*. Therefore horrible things happen when the compiler tries to call derived::print() on it, in this case it leads to a crash of the program.
When you access e->tame directly, also horrible things could happen (the compiler still treats e as a derived* while it only is a base*). In this case, by chance, it happens to print out the expected value anyway.
From the compiler standpoint, e is a "derived" object pointer.
From the runtime standpoint, e is pointing to a "base" object, so e->name_ is pointing to a random address. Eventhough you cast it, it doesn't change the fact that it is a "base" object that was allocated.
If you take a closer look, none of the derived constructors initializes the base name, and neither does the base constructor (which is the only one used).
So when you do e->print() the value you want to print is undefined.
When you manually set it, its no longer undefined. So a call to e->print() will work just fine
You could try this
In base class define a non-default constructor that receives a name
base(std::string name):tame(name){}
Related
Similar questions I found were more based on what this does; I understand the assignment of a base class pointer to a derived class, e.g Base* obj = new Derived() to be that the right side gets upcasted to a Base* type, but I would like to understand the mechanism for how this happens and how it allows for virtual to access derived class methods. From searching online, someone equated the above code to Base* obj = new (Base*)Derived, which is what led to this confusion. If this type-casting is going on at compile-time, why and how can virtual functions access the correct functions (the functions of the Derived class)? Further, if this casting happens in the way I read it, why do we get errors when we assign a non-inheriting class to Base* obj? Thanks, and apologies for the simplicity of the question. I'd like to understand what causes this behavior.
Note: for clarity, in my example, Derived publicly inherits from Base.
In a strict sense, the answer to "how does inheritance work at runtime?" is "however the compiler-writer designed it". I.e., the language specification only describes the behavior to be achieved, not the mechanism to achieve it.
In that light, the following should be seen as analogy. Compilers will do something analogous to the following:
Given a class Base:
class Base
{
int a;
int b;
public:
Base()
: a(5),
b(3)
{ }
virtual void foo() {}
virtual void bar() {}
};
The compiler will define two structures: one we'll call the "storage layout" -- this defines the relative locations of member variables and other book-keeping info for an object of the class; the second structure is the "virtual dispatch table" (or vtable). This is a structure of pointers to the implementations of the virtual methods for the class.
This figure gives an object of type Base
Now lets look as the equivalent structure for a derived class, Derived:
class Derived : public Base
{
int c;
public:
Derived()
: Base(),
c(4)
{ }
virtual void bar() //Override
{
c = a*5 + b*3;
}
};
For an object of type Derived, we have a similar structure:
The important observation is that the in-memory representation of both the member-variable storage and the vtable entries, for members a and b, and methods foo and bar, are identical between the base class and subclass. So a pointer of type Base * that happens to point to an object of type Derived will still implement an access to the variable a as a reference to the first storage offset after the vtable pointer. Likewise, calling ptr->bar() passes control to the method in the second slot of the vtable. If the object is of type Base, this is Base::bar(); if the object is of type Derived, this is Derived::bar().
In this analogy, the this pointer points to the member storage block. Hence, the implementation of Derived::bar() can access the member variable c by fetching the 3rd storage slot after the vtable pointer, relative to this. Note that this storage slot exists whenever Derived::bar() sits in the second vtable slot...i.e., when the object really is of type Derived.
A brief aside on the debugging insanity that can arise from corrupting the vtable pointer for compilers that use a literal vtable pointer at offset 0 from this:
#include <iostream>
class A
{
public:
virtual void foo()
{
std::cout << "A::foo()" << std::endl;
}
};
class B
{
public:
virtual void bar()
{
std::cout << "B::bar()" << std::endl;
}
};
int main(int argc, char *argv[])
{
A *a = new A();
B *b = new B();
std::cout << "A: ";
a->foo();
std::cout << "B: ";
b->bar();
//Frankenobject
*((void **)a) = *((void **)b); //Overwrite a's vtable ptr with b's.
std::cout << "Franken-AB: ";
a->foo();
}
Yields:
$ ./a.out
A: A::foo()
B: B::bar()
Franken-AB: B::bar()
$ g++ --version
g++ (Ubuntu 5.4.0-6ubuntu1~16.04.5) 5.4.0 20160609
...note the lack of an inheritance relationship between A and B... :scream:
Whoever says
Base* obj = new Derived();
is equivalent to
Base* obj = new (Base*)Derived;
is ignorant of the subject matter.
It's more like:
Derived* temp = new Derived;
Base* obj = temp;
The explicit cast is not necessary. The language permits a derived class pointer to be assigned to a base class pointer.
Most of the time the numerical value of the two pointers are same but they are not same when multiple inheritance or virtual inheritance is involved.
It's the compiler's responsibility to make sure that numerical value of the pointer is offset properly when converting a derived class pointer to a base class pointer. The compiler is able to do that since it makes the decision about the layout of the derived class and the base class sub-objects in the derived class object.
If this type-casting is going on at compile-time, why and how can virtual functions access the correct functions
There is no type casting. There is a type conversion. Regarding the virtual functions, please see How are virtual functions and vtable implemented?.
Further, if this casting happens in the way I read it, why do we get errors when we assign a non-inheriting class to Base* obj?
This is moot since it does not happen the way you thought they did.
I have two classes related by inheritance:-
class Base
{
public:
virtual void f(int x)
{
cout << "BASE::int" << endl;
}
virtual void f(double x)
{
cout << "BASE::double" << endl;
}
};
class Derived : public Base
{
public:
virtual void f(str::string s)
{
cout << "DERIVED::string" << endl;
}
};
I have provided same method in derived class with different parameters. That means rather than overriding I am hiding base class versions of this function. So, below calls are expected and clear to me.
std::string str("Hello");
Base b;
b.f(1); //calls base class version.
b.f(str); //error.
Derived d;
d.f(1); //error.
d.f(str); //calls derived class version.
But I am not able get clarification for this last scenario.
Base *b = new Derived;
b->f(str); //results in error.
Would compiler not bind this call to derived version of f using vtables and vptrs. But instead it's doing something else. Can anyone provide me complete path how compiler would try to resolve this call as per language mechanisms.
If your pointer is of type Base* then you can only "see" members that are defined in class Base. The compiler doesn't (or pretends not to) "know" that the variable really points to an instance of Derived, even if you just assigned one to it on the previous line.
When you declare a variable to be of type Base*, you're telling the compiler: treat this as something that could point to a Base or to any class derived from it. So you can't access members that are defined in a particular derived class, because there's no guarantee that the pointer actually points to an instance of that derived class.
The vtable only enters the picture at runtime. The generated assembly would have a lookup of the vptr value for a function and a jump to that address. This also means that the polymorphism is "restricted" to functions that Base knows about. Note that this is what makes more sense as well - the definition of a class should only depend on itself and its parents. If you wanted to make Base* b aware of the virtual functions implemented by Derived, you would end up with the number of vtable entries in Bases depending on its children.
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.
Given the following class structure:
class Base
{
virtual void outputMessage() { cout << "Base message!"; }
};
class Derived : public Base
{
virtual void outputMessage() { cout << "Derived message!"; }
}
.. and this code snippet:
Base baseObj;
Derived* convertedObj = (Derived*) &baseObj;
convertedObj->outputMessage();
.. the output will be "Base message!".
Is there any way to cast or manipulate the object to make Derived's version of the outputMessage method to be called polymorphically?
Edit: I will attempt to show the reason why I'm after this:
I am writing migration tools that hook into our main system. For this reason, I need to get access to protected member methods, or customise existing virtual methods. The former I can do by defining a derived class and casting objects to it, to call methods statically. What I can't do is change the behaviour for methods which I do not call statically (ie methods that are called elsewhere in the codebase).
I have also tried creating objects of the derived class directly, but this causes issues in other parts of the system due to the manipulation of the objects passed through the constructor.
No, virtual functions operate on the actual types of the object being pointed to, which in your case is just a simple Base.
Actually, with the down-casting, you're entering undefined-behaviour land here. This can blow off like a bomb with multiple inheritance, where the vtable in the derived class isn't at the same offset as the vtable in the base class.
No Standard-compliant solution
What you're trying to do isn't possible using behaviours guaranteed by the C++ Standard.
If you really MUST do this as a short-term measure to assist your migration, don't depend on it in production, and can adequately verify the behaviour, you could experiment as illustrated below.
Discussion of your attempt
What I'm showing is that you're taking the wrong approach: simply casting a pointer-to-base to a pointer-to-derived doesn't alter the object's vtable pointer.
Deriving a plausible hack
Addressing that, the naive approach is to reconstruct the object in place as a derived object ("placement" new), but this doesn't work either - it will reinitialise the base class members.
What you can possibly do is create a non-derived object that has no data members but the same virtual dispatch table entries (i.e. same virtual functions, same accessibility private/protected/public, same order).
More warnings and caveats
It may work (as it does on my Linux box), but use it at your own risk (I suggest not on production systems).
Further warning: this can only intercept virtual dispatch, and virtual functions can sometimes be dispatched statically when the compiler knows the types at compile time.
~/dev cat hack_vtable.cc
// change vtable of existing object to intercept virtual dispatch...
#include <iostream>
struct B
{
virtual void f() { std::cout << "B::f()\n"; }
std::string s_;
};
struct D : B
{
virtual void f() { std::cout << "D::f()\n"; }
};
struct E
{
virtual void f() { std::cout << "E::f()\n"; }
};
int main()
{
B* p = new B();
p->s_ = "hello";
new (p) D(); // WARNING: reconstructs B members
p->f();
std::cout << '\'' << p->s_ << "'\n"; // no longer "hello"
p->s_ = "world";
new (p) E();
p->f(); // correctly calls E::f()
std::cout << '\'' << p->s_ << "'\n"; // still "world"
}
~/dev try hack_vtable
make: `hack_vtable' is up to date.
D::f()
''
E::f()
'world'
Well, even if you're casting your Base object as a Derived one, internally, it's still a Base object: the vftable of your object (the actual map of functions to RAM pointers) is not updated.
I don't think there is any way to do what you want to do and I don't understand why you'd like to do it.
In this question downcast problem in c++ Robs answer should also be the answer to your problem.
Not at least in legal way. To call Derived class function, you need to have Derived object being referred.
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).