In object slicing,when a derived class object is copied to a Base class object , does the _vptr of Derived class also gets copied to _vptr of Base class like other members of class Base?.If not why?
class Base{
public :
virtual void Display(){cout<<"In Base"<<endl;}
};
class Derived:public Base{
public:
void Display(){cout<<"In Derived"<<endl;}
};
int main()
{
Derived objD;
Base objB;
objB = objD;
objB.Display();
}
I have observed the following result for the above snippet.
Output
In Base
The vptr is NOT copied. Let's try to reason about why.
Looking at your main function:
Derived objD;
Base objB;
objB = objD; // <-- HERE
objB.Display();
In line 3, you are assigning objD to objB. This is actually calling Base's assignment operator (which is automatically defined):
Base& operator=(const Base& other)
and it is being passed objD as a Base&. So, your question becomes, "Does the assignment operator copy the vptr"? The answer is, "no". The default assignment operator only copies fields on the class.
You may then ask, "Why wouldn't it copy the vptr too?" The reason is that, if it copied the vptr, methods on the Base class would end up using methods implemented on the Derived class. However, in full generality, those methods could use data members that only exists on the Derived class (and that don't exist on the Base class). Calling those methods would therefore be nonsensical (the data logically doesn't exist on the Base class), and so the language rightly chooses not to do this.
The main issue is that, when you assign the Derived class to the Base class, the variable you're assigning to only holds the fields for the Base class, so the fields in the Derived class that aren't in the Base class are not copied. Therefore, methods from the Derived class won't make sense when called on the Base class.
Note that this isn't the case if, instead, you were to assign a Base pointer or a Base reference to the Derived class. In that case, the original Derived class instance still exists. It's sitting in memory somewhere and has all the Base+Derived class fields. Therefore, methods for the Derived class called on that instance will have access to those fields, and so being able to call those methods still makes sense.
This is why, in C++, to do polymorphism (via virtual methods), you need to use a reference or pointer. See here for a similar discussion:
Why doesn't polymorphism work without pointers/references?
All known implementations use vptr but the details vary a lot. The vptr is a way for implementations to represent the type of an object of a polymorphic class (class with virtual functions) and sometimes classes with virtual base classes (very implementation dependent).
Note that in many cases involving more than simple inheritance (single non virtual inheritance) classes have more than one vptr.
The vptr value is a function of the type of the most derived object constructed.
The type of an object cannot be changed by the user during its lifetime; during construction, the type of the object changes as it is being constructed; during destruction, it changes back. (It is illegal to refer to an object during construction or destruction with a name or other expression that has a type that doesn't match the object.)
You can reuse the space of an existing object to construct an object of a different type, but it isn't the same object:
struct X {
A a;
B b;
// requires: construction doesn't throw
};
void replace (X &x) {
x.~X();
B &b = *new (&x) B; // hope no exception here
b.f(); // use as a normal B object
x.f(); // undefined: cannot use x as a real object
X *p = &x; // legal: x isn't used as an object, only as an address
b.~B(); // clean up ressources if needed
new (&x) X; // valid: &x refers to storage, as if a void*
// x refers to a valid X object
}
Such object reuse doesn't change the type of any existing object: replace(x) doesn't just act on x (it does by destructing one and reconstructing one), it acts on the storage location of x. After calling replace(x) the name x can be used to refer to the newly constructed X object, which has effectively taken the identify of the previously existing X object.
No operation on an object (that keeps the object alive) is even allowed to change its type in C++. There is no way for a vptr to change on a constructed object.
Changing the type of a declared object would wreck the C++ types system and the invariants of declared objects. The compiler wouldn't know what class to destroy, which virtual functions to call, where the base classes are, etc. It would completely change the way C++ works. It's hard to even imagine the semantics associated with changing the type of an existing object.
Related
Consider the below simple program of inheritance
#include <iostream>
class A
{
};
class B : public A
{
};
class C : public B
{
};
int main()
{
C x;
}
Now my question is
How many objects are created ? One or three?
Also, in case one object, does it mean it creates a layered object ?
What I wanted to ask was ,when we call constructor of base classes , what is happening as we have only one object (from the object perspective) ? What all things C object x will have ,and what all things are deleted when destructors of base class is called?
How is memory allocated for C's object?
Just to make everyone know ,I do understand
When we are creating an object of the derived class, we end up with one object only .
But the question is ,internally do the derived class object c will wrap the two objects of A and B or , will just public/protected attributes will be copied to the object.
Also is the below line correct?
"When we declare a object on the stack or use new first the memory is reserved and object is created, then the constructors are executed, starting with the base constructor and working upwards towards the most derived class ?"
Only one object of type class C would be created.
So basically in this case, constructors of base classes are called first before the constructor of the derived class is called. In the end, the object of derived class also contains the contents of bases classes.
One object is created, of type C, which contains all of the members of A, B, and C.
Here are some additional information about the relation between a base-class object and a derived-class object:
Every derived object contains a base-class part to which a pointer or reference of the base-class type can be bound. That's the reason why a conversion from derived to base exists, and no implicit Conversion from base to derived.
A base-class object can exist either as an independent object or as part of a derived object.
When we initialize or assign an object of a base type from an object of a derived type, only the base-class part of the derived object is copied, moved, or assigned. The derived part of the object is ignored.
see "C++ Primer Fifth Edition" §15.2.3
Let's say that I use an external library full of various classes. When I can safely inherit from one of those classes? I know that the base class must have a virtual destructor. Is there something else I should check before using the class as the base class? Can I be sure that it is safe only if the docs state so?
If the documentation states that it is safe to derive a type, follow the documentation. If, for some reason, it behaves in a way that goes against the documentation, then this is a problem with the library and is a bug for the authors to fix or offer workarounds for, because they are not committing to the API that they guarantee in the documentation.
Any type that is not final can be derived "safely"; what matters more is how this type is handled and destroyed. If you inherit from a type that has no virtual destructor, this doesn't inherently break anything; it just prevents having the derived type's destructor get called if you destroy that from a handle to the base.
If you only ever destroy the type from a handle to the derived type, (e.g. you either hold it concretely, or never destroy it from a handle to the base), then this has no consequence.
To better explain my point, imagine the following hierarchy:
class Base {
public:
// No virtual destructor
...
};
class Derived : public Base {
public:
...
private:
std::string m_something; // some leakable object
};
The derivation of Derived from Base is completely safe to do. What matters is how it gets destroyed for whether there will be a problem. For this there are two different cases to consider: Automatic and Dynamic cases.
Automatic Objects
Automatic types ("by-value" types) are safe, regardless of whether they have static lifetime or not
auto d = Derived{ ... };
static auto sd = Derived{ ... };
At the end of their lifetime, the destructor Derived::~Derived will be called, since the type is concretely known
Dynamic Objects
Dynamic objects don't get destroyed on their own. Their resources need to be cleaned up eventually, either automatically with RAII in a smart pointer, by someone calling delete, or by someone explicitly calling ~T() and freeing the memory.
These are still safe if they are destroyed by a handle to the derived type, but will not be if they are destroyed by a handle to the base.
auto* d1 = new Derived{ ... };
auto* d2 = new Derived{ ... };
// Deleting as a pointer to Base; ~Derived won't be called because ~Base is virtual
// This would be a memory leak
delete static_cast<Base*>(d1); // bad
// Deleting as a pointer to Derived -- ~Derived will be called, this is fine
delete d2; // good
In terms of Smart Pointer types:
Shared Pointer
shared_ptr types are safe, since they always destroy objects from the concrete type -- even if they get aliased to a base class.
void accept_base(std::shared_ptr<Base> b);
auto d = std::make_shared<Derived>(...);
// still safe
accept_base(std::move(d));
Unique Pointer
unique_ptr types are not safe by default due to the default deleter deleting based on the T type of unique_ptr.
For example:
auto d = std::make_unique<Derived>(...);
auto b = std::unique_ptr<Base>{std::move(d)};
// b will be destroyed at end of scope by calling ~Base, which is not virtual!
Even with all of this said: If you're using a library that explicitly states that you are meant to derive some XYZ class, then you should still assume that this is how the class should be used. At that point, if something undesirable occurs, it will be up to the library maintainer to ensure that their code performs as documented, since it's part of their expressly stated API.
If you intend to call methods from a Base class reference or pointer, you should also check if they are declared virtual.
Apart from that I would look into the documentation of the class and whether it is declared final
You actually do not need a virtual destructor for it to be safe to inherit from a class. You only need a virtual destructor, if you want to use (and thereby destroy) the class from a pointer to its base class.
It all depends on how you intend to use the derived class.
For instance, if you just want to make a class that inherits from the given class, but you do not intend to use it in a base class pointer or reference.
Base baseObj;
Derived derivedObject; // This does not create any problems
If you want to use it from a pointer or reference (this also applies to smart pointers of course) to the base class like this:
Base* basePtr = new Base();
Base* basePtrToDerived = new Derived();
Derived* derivedPtrToDerived = new Derived();
// Do stuff here
delete basePtr;
delete basePtrToDerived; // if Base has no virtual destructor, only the destructor of Base is called
delete derivedPtrToDerived; // This will always call the destructor of Derived
you need a virtual destructor.
Is the object slicing that occurs when assigning a derived object through a base class reference (without a virtual operator=) a well-defined operation? I.e., is it guaranteed by the standard to leave the derived parts of the object untouched?
In many questions regarding object slicing here and elsewhere, an example like the following is given:
struct Base{
int x;
Base(int xx) :x(xx) {}
virtual void print() const {std::cout << "Base("<<x<<")\n";}
};
struct Derived : Base{
int y;
Derived(int xx, int yy ) :Base(xx),y(yy){}
void print() const {std::cout << "Derived("<<x<<","<<y<<")\n";}
};
int main()
{
Derived d1{1,2};
Derived d2{3,4};
Base& br = d1;
br = d2; // assign a Derived through a Base&
br.print(); // prints Derived(3,2)
}
The example is intended to show that when assigning through a Base& it only assigns the Base class members and leaves the members in Derived untouched.
Building the above example with -fsanitize=undefined does not complain, and it produces the expected output on all systems I've run it.
The question is, is this guaranteed by the standard? In my understanding it is, as Base::operator= cannot write outside the Base part of the object, and the Derived part of the object (here int y) cannot have any overlap with the Base part.
Is there some corner case I am missing? (There are of course many ways having an inconsistent object can lead to undefined behaviour, but my question is limited to what happens during the assignment operation.)
Base& br = d1;
This creates a reference to a Base object. This will now be referencing a Base object that's just as well-formed as any other Base object (in a well-formed C++ program). In all respects, the referenced Base object is identical to all other Base objects that may or may not exist. This object can be assigned to just like any other Base object can be assigned to, and the exact same thing will happen to this object as to any other Base object that gets assigned to. The End.
Objects that are base objects of other objects are not any different than objects that are not, when viewed through the prism of those objects alone. They are well-formed objects of their own, and are just like any other Base object (ignoring things like virtual methods here). This is a fundamental concept in C++.
It would be rather inconvenient if assigning to a Base object suddenly "writes" somewhere else. It would be rather difficult to accomplish anything in C++, in that case. Of course, it goes without saying that one can always overload operator=, and then the sky's the limit. But from a practical point, as long as the = operator works the way it's expected to work, assigning to a Base object won't do anything to anything that's not a part of that Base object.
Is object slicing by assigning through a base reference well-defined?
Yes. Slicing is well defined operation.
is it guaranteed by the standard to leave the derived parts of the object untouched?
The implicitly generated assignment operator of the base won't touch derived parts. A custom one could do so, although such design is uncommon.
Every class which contains one or more virtual function has a Vtable associated with it. A void pointer called vptr points to that vtable. Every object of that class contains that vptr which points to the same Vtable. Then why isn't vptr static ? Instead of associating the vptr with the object, why not associate it with the class ?
The runtime class of the object is a property of the object itself. In effect, vptr represents the runtime class, and therefore can't be static. What it points to, however, can be shared by all instances of the same runtime class.
Your diagram is wrong. There is not a single vtable, there is one vtable for each polymorphic type. The vptr for A points to the vtable for A, the vptr for A1 points to the vtable for A1 etc.
Given:
class A {
public:
virtual void foo();
virtual void bar();
};
class A1 : public A {
virtual void foo();
};
class A2 : public A {
virtual void foo();
};
class A3 : public A {
virtual void bar();
virtual void baz();
};
The vtable for A contains { &A::foo, &A::bar }
The vtable for A1 contains { &A1::foo, &A::bar }
The vtable for A2 contains { &A2::foo, &A::bar }
The vtable for A3 contains { &A::foo, &A3::bar, &A3::baz }
So when you call a.foo() the compiler follows the object's vptr to find the vtable then calls the first function in the vtable.
Suppose a compiler uses your idea, and we write:
A1 a1;
A2 a2;
A& a = (std::rand() % 2) ? a1 : a2;
a.foo();
The compiler looks in the base class A and finds the vptr for the class A which (according to your idea) is a static property of the type A not a member of the object that the reference a is bound to. Does that vptr point to the vtable for A, or A1 or A2 or something else? If it pointed to the vtable for A1 it would be wrong 50% of the time when a refers to a2, and vice versa.
Now suppose that we write:
A1 a1;
A2 a2;
A& a = a1;
A& aa = a2;
a.foo();
aa.foo();
a and aa are both references to A, but they need two different vptrs, one pointing to the vtable for A1 and one pointing to the vtable for A2. If the vptr is a static member of A how can it have two values at once? The only logical, consistent choice is that the static vptr of A points to the vtable for A.
But that means the call a.foo() calls A::foo() when it should call A1::foo(), and the call aa.foo() also calls A::foo() when it should call A2::foo().
Clearly your idea fails to implement the required semantics, proving that a compiler using your idea cannot be a C++ compiler. There is no way for the compiler to get the vtable for A1 from a without either knowing what the derived type is (which is impossible in general, the reference-to-base could have been returned from a function defined in a different library and could refer to a derived type that hasn't even been written yet!) or by having the vptr stored directly in the object.
The vptr must be different for a1 and a2, and must be accessible without knowing the dynamic type when accessing them through a poiner or reference to base, so that when you obtain the vptr through the reference to the base class, a, it still points to the right vtable, not the base class vtable. The most obvious way to do this is to store the vptr directly in the object. An alternative, more complicated solution would be to keep a map of object addresses to vptrs, e.g. something like std::map<void*, vtable*>, and find the vtable for a by looking up &a, but this still stores one vptr per object not one per type, and would require a lot more work (and dynamic allocation) to update the map every time polymorphic objects are created and destroyed, and would increase overall memory usage because the map structure would take up space. It's simpler just to embed the vptr in the objects themselves.
The virtual table (which is, by the way, an implementation mechanism not mentioned in the C++ standard) is used to identify the dynamic type of an object at runtime. Therefore, the object itself must hold a pointer to it. If it was static, then only the static type could be identified by it and it would be useless.
If you are thinking of somehow using typeid() internally to identify the dynamic type and then call the static pointer with it, be aware that typeid() only returns the dynamic type for objects belonging to types with virtual functions; otherwise it just returns the static type (§ 5.2.8 in the current C++ standard). Yes, this means that it works the other way around: typeid() typically uses the virtual pointer to identify the dynamic type.
As everyone attest Vptr is a property of an object.
Lets see why?
Assume we have three objects
Class Base{
virtual ~Base();
//Class Definition
};
Class Derived: public Base{
//Class Definition
};
Class Client: public Derived{
//Class Definition
};
holding relation Base<---Derived<----Client.
Client Class is derived from Derived Class which is in turn derived from Base
Base * Ob = new Base;
Derived * Od = new Derived;
Client* Oc = new Client;
Whenever Oc is destructed it should destruct base part, derived part and then client part of the data. To aid in this sequence Base destructor should be virtual and object Oc's destructor is pointing to Client's destructor. When object Oc's base destructor is virtual compiler adds code to destructor of object Oc to call derived's destructor and derived destructor to call base's destructor. This chaining sees all the base, derived and client data is destructed when Client object is destroyed.
If that vptr is static then Oc's vtable entry will still be pointing to Base's destructor and only base part of Oc is destroyed. Oc's vptr should always point to most derived object's destructor, which is not possible if vptr is static.
The whole point of the vptr is because you don't know exactly which class an object has at runtime. If you knew that, then the virtual function call would be unnecessary. That is, in fact, what happens when you're not using virtual functions. But with virtual functions, if I have
class Sub : Parent {};
and a value of type Parent*, I don't know at runtime if this is really an object of type Parent or one of type Sub. The vptr lets me figure that out.
virtual method table is per class. An object contains a pointer to the run-time type vptr.
I don't think this is a requirement in the standard bust all compiles that I've worked with do it this way.
This is true even in you example.
#Harsh Maurya: Reason might be , Static member variables must be defined before Main function in the program. But if we want _vptr to be static, whose responsibility ( compiler/programmer ) to define the _vptr in the program before main. And how programmer knows the pointer of VTABLE to assign it to _vptr. Thats why compiler took that responsibility to assign the value to pointer(_vptr). This happens in Constructor of class(Hidden functionality). And now if Constructor comes into picture there should be one _vptr for each object.
I have a class with protected constructor:
class B {
protected:
B(){};
};
Now I derive from it and define two static functions and I manage to actually create objects of the class B, but not on the heap:
class A : public B {
public:
static B createOnStack() {return B();}
//static B* createOnHeap() {return new B;} //Compile time Error on VS2010
};
B b = A::createOnStack(); //This works on VS2010!
The question is: 1) Is VS2010 wrong in allowing the first case? 2) Is it possible to create objects of B without modifying B in any way (no friendship and no extra functions).
I am asking, because it is possible to make something similar when dealing with instances of B and its member functions, see:
http://accu.org/index.php/journals/296
Thank you in advance for any suggestion!
Kind regards
Yes, this code is non-compliant. This is related to special rules for protected member access (C++03 draft, 11.5/1):
When a friend or a member function of a derived class references a protected nonstatic member function or
protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11.10). Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5).
When you use B() or new B(), you're effectively using the constructor through a pointer to the base class.
You can create an object of type A (I assume that A is as posted - no additional members/non-static functions) and use it instead. If you're creating it on stack, everything should work fine, unless you're trying to assign other objects of type B to it. If you're creating it on heap, everything is fine as long as B's destructor is virtual. If B's destructor is not virtual, and you're returning new A() as a B*, then deleting the pointer is technically undefined behavior (5.3.5/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.
However you'll probably find it working fine in practice, so you can rely on the actual behavior if there is no other workaround (i.e. use it as a last resort).
There is a common misunderstanding on what protected actually means. It means that the derived class can access that particular member on itself not on other objects. The compiler should have rejected both functions as in both cases it is accessing the constructor of an object that is not of the derived type.
Another example, easier to discuss for its correctness would be:
struct base {
protected:
int x;
};
struct derived : base{
static void modify( base& b ) {
b.x = 5; // error
}
};
The commented line is an error as it is trying to modify an object of type base, not necessarily a derived object. If the language allowed that code to compile, then you would be able to modify an object of type base or even objects of types derived1, derived2... effectively breaking access rules.
struct derived2 : base {};
int main() {
base b;
derived2 d;
derived::modify( b ); // modifying a base!!!
derived::modify( d ); // modifying a derived2!!!
}