C++ ISO Standard interpretation of dereferencing pointer to base - c++

I would like to know standard's view on dereferencing pointer to base, but I'm not making any progress finding it. Take these two classes for example:
class Base
{
public:
virtual void do_something() = 0;
};
class Derived : public Base
{
public:
virtual void do_something();
};
void foo2(Base *b)
{
Base &b1 = *b; // how this work by standard?
}
void foo()
{
Derived *d = new Derived();
foo2(d); // does this work by standard?
}
So, basically, if pointer of type B to an object of type D is dereferenced, will slicing happen in place, or temporary will emerge? I'm prone to believe that temporary is not an option, because that would mean that temporary is instance of abstract class.
Whatever the truth, I would appreciate any pointers to the ISO standard that says one or the other. (Or third, for that matter. :) )
EDIT:
I threw the point with temporary not being an option as a possible line of reasoning why it behaves the way it does, which is quite logical, but I can't find confirmation in standard, and I'm not a regular reader.
EDIT2:
Through discussion, it became obvious that my question was actually about dereferencing a pointer mechanism, and not about splicing or temporaries. I thank everyone for trying to dumb it down for me, and I finally got answer to the question the puzzled me the most: Why I can't find anything in the standard about this... Obviously it was the wrong question, but I've got the right answer.
Thnx

Base &b = *static_cast<Base *>(d); // does this work by standard?
Yes.
But you can simply do this:
Base &b = *d;
//use b polymorphically!
b.do_something(); //calls Derived::do_something()
No need to use static_cast. After all, Derived is derived from Base.
Reply to your edit:
foo2(d); // does this work by standard?
Yes. Pointer of type Base* can be initialized with pointer of type Derived*.
--
Base &b = *b; // how this work by standard?
No. They're same name. If you mean, Base &b1 = *b, then yes, that works. b1 refers to the object pointed to by b.

Object slicing only occurs when the copy constructor or the assignment operator of the base class gets involved somehow, like in parameter passing by value. You can easily avoid these errors by inheriting from Boost's noncopyable for example, even if only in DEBUG mode.
Neither casting pointers or references nor dereferencing involve any copy construction or assignment. Making a Base reference from a Derived reference is perfectly safe, it's even a standard implicit conversion.

In my C++11 draft, 10 [class.derived] /1 says
[ Note: The scope resolution operator :: (5.1) can be used to refer to
a direct or indirect base member explicitly. This allows access to a
name that has been redeclared in the derived class. A derived class
can itself serve as a base class subject to access control; see 11.2.
A pointer to a derived class can be implicitly converted to a pointer
to an accessible unambiguous base class (4.10). An lvalue of a
derived class type can be bound to a reference to an accessible
unambiguous base class (8.5.3). —end note ]
In most implementations, your foo2 function will store Base& b as a Base*. It obviously can't be a Base itself, because that would be a copy, not a reference. Since it acts (at runtime, not syntactically) like a pointer instead of a copy, there's no splicing concerns.
In your code before your edit, the compiler would know that Base& b was actually d, it would be syntactic sugar, and wouldn't even generate a pointer in the assembly.

Related

Can you static_cast "this" to a derived class in a base class constructor then use the result later?

We ran into this scenario in our codebase at my work, and we had a big debate over whether this is valid C++ or not. Here is the simplest code example I could come up with:
template <class T>
class A {
public:
A() { subclass = static_cast<T*>(this); }
virtual void Foo() = 0;
protected:
T* subclass;
};
class C : public A<C> {
public:
C(int i) : i(i) { }
virtual void Foo() { subclass->Bar(); }
void Bar() { std::cout << "i is " << i << std::endl; }
private:
int i;
};
int main() {
C c(5);
c.Foo();
return 0;
}
This code works 100% of the time in practice (as long as the template parameter type matches the subclass type), but if we run it through a runtime analyzer, it tells us that the static_cast is invalid because we're casting this to a C* but the C constructor hasn't run yet. Sure enough, if we change the static_cast to a dynamic_cast, it returns nullptr and this program will fail and crash when accessing i in Bar().
My intuition is that it should always be possible to replace static_cast with dynamic_cast without breaking your code, suggesting that the original code in fact is depending on compiler-specific undefined behavior. However, on cppreference it says:
If the object expression refers or points to is actually a base class subobject of an object of type D, the result refers to the enclosing object of type D.
The question being, is it a base class subobject of an object of type D before the object of type D has finished being constructed? Or is this undefined behavior? My level of C++ rules lawyering is not strong enough to work this out.
In my opinion this is well-defined according to the current wording of the standard: the C object exists at the time of the static_cast, although it is under construction and its lifetime has not yet begun. This would seem to make the static_cast well-defined according to [expr.static.cast]/11, which reads in part:
... If the prvalue of type “pointer to cv1 B” points to a B that is actually a base class subobject of an object of type D, the resulting pointer points to the enclosing object of type D. Otherwise, the behavior is undefined.
It doesn't say that the D object's lifetime must have begun.
We might also want to look at the explicit rule about when it becomes legal to perform an implicit conversion from derived to base, [class.cdtor]/3:
To explicitly or implicitly convert a pointer (a glvalue) referring to an object of class X to a pointer (reference) to a direct or indirect base class B of X, the construction of X and the construction of all of its direct or indirect bases that directly or indirectly derive from B shall have started and the destruction of these classes shall not have completed, otherwise the conversion results in undefined behavior. To form a pointer to (or access the value of) a direct non-static member of an object obj, the construction of obj shall have started and its destruction shall not have completed, otherwise the computation of the pointer value (or accessing the member value) results in undefined behavior.
According to this rule, as soon as the compiler starts constructing the base class A<C>, it is well-defined to implicitly convert from C* to A<C>*. Before that point, it results in UB. The reason for this, basically, has to do with virtual base classes: if the path by which A<C> is inherited by C contains any virtual inheritance, the conversion may rely on data that are set up by one of the constructors in the chain. For a conversion from base to derived, if there is indeed any virtual inheritance on the chain, static_cast will not compile, so we don't really need to ask ourselves the question, but are those data sufficient for going the other way?
I really can't see anything in the text of the standard, nor any rationale, for the static_cast in your example not being well-defined, nor in any other case of static_casting from base to derived when the reverse implicit conversion (or static_cast) would be allowed (excepting the case of virtual inheritance, which as I said before, leads to a compile error anyway).
(Would it be well-defined to do it even earlier? In most cases this won't be possible; how could you possibly attempt to static_cast from B* to D* before the conversion from D* to B* is allowed, without having obtained the B* pointer precisely by doing the latter? If the answer is that you got from D* to B* through an intermediate base class C1 whose constructor has started, but there is another intermediate base class C2 sharing the same B base class subobject and its construction hasn't started yet, then B is a virtual base class, and again, this means the compiler will stop you from then trying to static_cast from B* back down to D*. So I think there are no issues left to resolve here.)

Converting Derived** to Base** and Derived* to Base*

Ok, I was reading through this entry in the FQA dealing about the issue of converting a Derived** to a Base** and why it is forbidden, and I got that the problem is that you could assign to a Base* something which is not a Derived*, so we forbid that.
So far, so good.
But, if we apply that principle in depth, why aren't we forbidding such example?
void nasty_function(Base *b)
{
*b = Base(3); // Ouch!
}
int main(int argc, char **argv)
{
Derived *d = new Derived;
nasty_function(d); // Ooops, now *d points to a Base. What would happen now?
}
I agree that nasty_function does something idiotic, so we could say that letting that kind of conversion is fine because we enable interesting designs, but we could say that also for the double-indirection: you got a Base **, but you shouldn't assign anything to its deference because you really don't know where that Base ** comes, just like the Base *.
So, the question: what's special about that extra-level-of-indirection? Maybe the point is that, with just one level of indirection, we could play with virtual operator= to avoid that, while the same machinery isn't available on plain pointers?
nasty_function(d); // Ooops, now *d points to a Base. What would happen now?
No, it doesn't. It points to a Derived. The function simply changed the Base subobject in the existing Derived object. Consider:
#include <cassert>
struct Base {
Base(int x) : x(x) {}
int x;
};
struct Derived : Base {
Derived(int x, int y) : Base(x), y(y) {}
int y;
};
int main(int argc, char **argv)
{
Derived d(1,2); // seriously, WTF is it with people and new?
// You don't need new to use pointers
// Stop it already
assert(d.x == 1);
assert(d.y == 2);
nasty_function(&d);
assert(d.x == 3);
assert(d.y == 2);
}
d doesn't magically become a Base, does it? It's still a Derived, but the Base part of it changed.
In pictures :)
This is what Base and Derived objects look like:
When we have two levels of indirection it doesn't work because the things being assigned are pointers:
Notice how neither of the Base or Derived objects in question are attempted to be changed: only the middle pointer is.
But, when you only have one level of indirection, the code modifies the object itself, in a way that the object allows (it can forbid it by making private, hiding, or deleting the assignment operator from a Base):
Notice how no pointers are changed here. This is just like any other operation that changes part of an object, like d.y = 42;.
No, nasty_function() isn't as nasty as it sounds. As the pointer b points to something that is-a Base, it's perfectly legal to assign a Base-value to it.
Take care: your "Ooops" comment is not correct: d still points to the same Derived as before the call! Only, the Base part of it was reassigned (by value!). If that gets your whole Derived out of consistency, you need to redesign by making Base::operator=() virtual. Then, in the nasty_function(), in fact the Derived assignment operator will be called (if defined).
So, I think, your example does not have that much to do with the pointer-to-pointer case.
*b = Base(3) calls Base::operator=(const Base&), which is actually present in Derived as member functions (inc. operators) are inherited.
What would happen then (calling Derived::operator=(const Base&)) is sometimes called "slicing", and yes, it's bad (usually). It's a sad consequence of the sheer omnipresence of the "become-like" operator (the =) in C++.
(Note that the "become-like" operator doesn't exist in most OO languages like Java, C# or Python; = in object contexts there means reference assignment, which is like pointer assignment in C++;).
Summing up:
Casts Derived** -> Base** are forbidden, because they can cause a type error, because then you could end up with a pointer of type Derived* pointing to an object of type Base.
The problem you mentioned isn't a type error; it's a different type of error: mis-use of the interface of the derived object, rooting from the sorry fact that it has inherited the "become-like" operator of its parent class.
(Yes, I call op= in objects contexts "become-like" deliberately, as I feel that "assignment" isn't a good name to show what's happening here.)
Well the code you gave makes sense. Indeed the assignement operator cannot overrite data specific to Derived but only base. Virtual functions are still from Derived and not from Base.
*b = Base(3); // Ouch!
Here the object at *b really is a B, it's the base sub-object of *d. Only that base sub-object gets modified, the rest of the derived object isn't changed and d still points to the same object of the derived type.
You might not want to allow the base to be modified, but in terms if the type system it's correct. A Derived is a Base.
That's not true for the illegal pointer case. A Derived* is convertible to Base* but is not the same type. It violates the type system.
Allowing the conversion you're asking about would be no different to this:
Derived* d;
Base b;
d = &b;
d->x;
Reading through the good answers of my question I think I got the point of the issue, which comes from first principles in OO and has nothing to do with sub-objects and operator overloading.
The point is that you can use a Derived whenever a Base is required (substitution principle), but you cannot use a Derived* whenever a Base* is needed due to the possibility of assigning pointers of instances of derived classes to it.
Take a function with this prototype:
void f(Base **b)
f can do a bunch of things with b, dereferencing it among other things:
void f(Base **b)
{
Base *pb = *b;
...
}
If we passed to f a Derived**, it means that we are using a Derived* as a Base*, which is incorrect since we may assign a OtherDerived* to Base* but not to Derived*.
On the other way, take this function:
void f(Base *b)
If f dereferences b, then we would use a Derived in place of a Base, which is entirerly fine (provided that you give a correct implementation of your class hierarchies):
void f(Base *b)
{
Base pb = *b; // *b is a Derived? No problem!
}
To say it in another way: the substitution principles (use a derived class instead of the base one) works on instances, not on pointers, because the "concept" of a pointer to A is "points to an instance of whichever class inherits A", and the set of classes which inherits Base strictly contains the set of classes that inherits Derived.

Does dynamic_cast really work for multiple inheritance?

I wanted to see if it's possible to create "interfaces", inherit them, and then check at runtime if any random class implements that interface. This is what I have:
struct GameObject {
int x,y;
std::string name;
virtual void blah() { };
};
struct Airholder {
int oxygen;
int nitrogen;
};
struct Turf : public GameObject, public Airholder {
Turf() : GameObject() {
name = "Turf";
}
void blah() { };
};
void remove_air(GameObject* o) {
Airholder* a = dynamic_cast<Airholder*>(o);
if(!a) return;
a->oxygen = 0;
a->nitrogen = 0;
};
Now, it works. The documentation says that it works, the test example works.. But also, it didn't compile until I added a virtual method to GameObject. The thing is, I really don't know if the feature is intended to be used like that. What made me wonder there is the fact that I have to declare a virtual function for the class I'm checking. But obviously, there is none, the class I'm checking itself has no virtual functions, in fact my whole code has nothing to do with virtual functions, it's an entirely different approach.
So, I guess my question is: If what I'm doing really works, why do I need a virtual function to give my class a vtable? Why can't I declare the class a "runtime type" or something without virtual functions?
§ 5.2.7 of the standard says:
The result of the expression dynamic_cast(v) is the result of converting the expression v to type
T. T shall be a pointer or reference to a complete class type, or “pointer to cv void”. Types shall not be
defined in a dynamic_cast. The dynamic_cast operator shall not cast away constness (5.2.11).
If T is a pointer type, v shall be an rvalue of a pointer to complete class type, and the result is an rvalue of
type T. If T is a reference type, v shall be an lvalue of a complete class type, and the result is an lvalue of
the type referred to by T.
If the type of v is the same as the required result type (which, for convenience, will be called R in this
description), or it is the same as R except that the class object type in R is more cv-qualified than the class
object type in v, the result is v (converted if necessary).
If the value of v is a null pointer value in the pointer case, the result is the null pointer value of type R.
If T is “pointer to cv1 B” and v has type “pointer to cv2 D” such that B is a base class of D, the result is a
pointer to the unique B sub-object of the D object pointed to by v. Similarly, if T is “reference to cv1 B”
and v has type “cv2 D” such that B is a base class of D, the result is an lvalue for the unique60) B sub-object
of the D object referred to by v. In both the pointer and reference cases, cv1 shall be the same cvqualification
as, or greater cv-qualification than, cv2, and B shall be an accessible unambiguous base class
of D. [Example:
struct B {};
struct D : B {};
void foo(D* dp)
{
B* bp = dynamic_cast(dp); // equivalent to B* bp = dp;
}
—end example]
Otherwise, v shall be a pointer to or an lvalue of a polymorphic type (10.3).
And to make a type polymorphic, it needs a virtual function, as per § 10.3:
Virtual functions support dynamic binding and object-oriented programming. A class that declares or
inherits a virtual function is called a polymorphic class.
So the reason why is "because the standard says so." That doesn't really tell you why the standard says so though, but the other answers cover that well I think.
So, I guess my question is: If what I'm doing really works, why do I need a virtual function to give my class a vtable? Why can't I declare the class a "runtime type" or something without virtual functions?
The presence of a virtual function is what makes a class polymorphic in C++. dynamic_cast<> only works with polymorphic classes. (The compiler will reject a dynamic cast on a non-polymorphic object.)
Polymorphism has a cost, both in time and in space (memory). Calls to virtual functions are now indirect, typically implemented in terms of a virtual table. In some critical places, those costs are simply unacceptable. So the language provides means of avoiding these costs.
Similar concepts exist elsewhere in the language. The underlying principle is that if you don't want to use some high-falutin' feature you shouldn't have to pay for the fact the some people do want to use it.
dynamic_cast requires the type to be polymorphic, and without any virtual methods (or at least a virtual destructor) a type is not (run-time) polymorphic. Simple inheritance is not enough. The run-time type information used by dynamic_cast is stored alongside the vtable if remember correctly.
There are two main reasons. The first is that there's just no use case for it. The point of inheritance is virtual functions. If you're not using virtual functions, don't use inheritance.
The second is that it's very complex to actually implement dynamic_cast that works without virtual functions due to the C++ compilation model. The only way to realistically implement dynamic_cast is to operate on the virtual table- a binary blob of data is typeless. You could define a class and then only dynamic_cast it in one TU- now one TU thinks the class has a vtable and one doesn't. That would be instant bad. Allowing dynamic_cast on classes that do not already have virtual functions would be, well, export, which means "Exceedingly difficult to implement".
As others have said, you need at least one virtual function to make a class polymorphic. Why this matters is that dynamic_cast itself is a polymorphic operation! Given a base class pointer, it returns different results based on the actual object it is called on.
C++ has a "don't pay for what you don't need" philosophy, thus the vtable (or whatever mechanism the compiler uses) is not provided unless there's a need as determined by the presence of a virtual function. Evidently the designers of C++ thought this was a reasonable requirement for the proper operation of dynamic_cast or they would have provided a way to generate a vtable without it.
[EDIT] According to the comments (people way smarter than me) my answer is completely wrong. However, make your destructors virtual anyway. [/EDIT]
In C++, I consider upcasting to a base type is only safe if the destructor is virtual. Technically it's safe, but in reality, you almost always want a virtual destructor. For instance:
class Base {
int thingy;
};
class Derived : Base{
int *array;
Derived() {array = new int[100];}
~Derived() {delete [] array;}
};
int main() {
std::auto_ptr<Base> obj(dynamic_cast<Base*>(new Derived));
}
In this example, when obj goes out of scope, the auto_ptr automatically calls the Base's destructor, but does not call the Derived deconstructor because the type is a Base, not a Derived. [Edit: corrections] This causes Undefined behaviour (at the very best, it causes a memory leak). I haven't any idea why C++ doesn't require a virtual destructor to compile down casts, it really should.

Base class holding a reference to Derived

I'd like to do this:
struct Derived;
struct Base{
Derived const& m_ref;
Base(Derived const& ref) : m_ref(ref){}
};
struct Derived: Base{
Derived(): Base(*this){}
};
But I seem to get unreliable behaviour (when used later on, m_ref points to things that aren't valid Derived).
Is it permissible to construct a reference to Derived from *this before the class has been initialised?
I appreciate that it is not valid to use such a reference until it has been initialised, but I don't see how changes to the initialisation of a class can affect references to it (since initialising it doesn't move it around in memory...).
I'm not sure what to call what I'm trying to do, so my search for information on this has drawn a blank...
Update:
I can't reproduce my problems with a simple test case, so it looks like it is probably okay (though I can't prove it, and would still welcome a definitive answer).
Suspect my problems arose from a broken copy-assignment operator. That's another matter altogether though!
Update 2
My copy constructor and copy-assignment operators were indeed to blame, and now this seems to work reliably. Still interested in whether or not it is well-defined behaviour though.
3.8/1 says:
The lifetime of an object of type T
begins when: — storage with the proper
alignment and size for type T is
obtained, and — if T is a class type
with a non-trivial constructor (12.1),
the constructor call has completed.
3.8/5 says:
Before the lifetime of an object has started but after the storage which the object will occupy has been allocated
or, after the lifetime of an object has ended and before the storage which the object occupied is
reused or released, any pointer that refers to the storage location where the object will be or was located
may be used but only in limited ways. Such a pointer refers to allocated storage (3.7.3.2), and using the
pointer as if the pointer were of type void*, is well-defined. Such a pointer may be dereferenced but the
resulting lvalue may only be used in limited ways, as described below.
"Below" is 3.8/6:
Such an lvalue refers to allocated storage (3.7.3.2), and using the properties of the lvalue which do not
depend on its value is well-defined.
...and then a list of things you can't do. Binding to a reference to the same, derived type is not among them.
I can't find anything elsewhere that might make your code invalid. Notably, despite the following phrase in 8.3.2/4:
A reference shall be initialized to
refer to a valid object or function.
there doesn't seem to be any definition of "valid object" to speak of.
So, after much to-ing and fro-ing, I must conclude that it is legal.
Of course, that's not to say that it's in any way a good idea! It still looks like a bad design.
For example, if you later change your base constructor and any of the following become relevant (again from 3.8/6):
the lvalue is used to access a non-static data member or call a non-static member function of the object
the lvalue is implicitly converted (4.10) to a reference to a base class type
the lvalue is used as the operand of a static_cast (5.2.9) (except when the conversion is ultimately to char& or unsigned char&
the lvalue is used as the operand of a dynamic_cast (5.2.7) or as the operand of typeid.
...then your program will be undefined, and the compiler may emit no diagnostic for this!
Random other observations
I notice a couple of other interesting things whilst compiling this answer, and this is as good a place as any to share them.
First, 9.3.2 appears to leave the type of this in a ctor-initializer accidentally unspecified. Bizarre!
Second, the criteria set on a pointer by 3.8/5 (not the same list that I quoted from 3.8/6) include:
If the object will be or was of a
non-POD class type, the program has
undefined behavior if [..] the
pointer is implicitly converted (4.10)
to a pointer to a base class type.
I believe that this renders the following innocuous-looking code undefined:
struct A {
A(A* ptr) {}
};
struct B : A {
B() : A(this) {}
};
int main() {
B b;
}
I think in general you're OK doing this, but be very careful in constructors and destructors. In particular, in Base::~Base, the Derived part of the object has already been destroyed so don't use m_ref there.
3.8/6 says what you can do with a pointer/reference to memory for an object that has been allocated but not yet constructed. Your code doesn't provoke an lvalue-to-rvalue conversion, or otherwise break the rules, so I'd think that you're fine. Since you're observing bad values, though, I may well have missed something. Or your code might be otherwise bad.
Even if you did break those rules, 12.6.2 and 12.7 list additional things that you can do during construction and destruction.
Edit: ah, 8.3.2/4: "A reference shall be initialized to refer to a valid object
or function." You initialize m_ref to refer to an object whose constructor hasn't even been entered yet. I don't know without further research whether an object under construction is "valid" or not, and in particular whether the object of most-derived type is "valid" at the time of construction of the base class. This could perhaps be the problem, though.
You might think that no unconstructed object is "valid", but then this would be invalid:
class Foo {
Foo() {
Foo &self = *this; // reference initialized to refer to unconstructed object!
}
};
So, is that invalid? If not, does the most-derived object become valid somewhere between the start of the base class constructor call and the start of the derived class constructor call? I dunno, sorry.
I think the big problem in this is that you think you want to do one thing, when in reality you actually want to do something else. Strange, huh?
Is it permissible to construct a reference to Derived from *this before the class has been initialised?
Yes, as long as you don't use it (for anything but storing a reference to it) in the scope of the Base constructor and remember in ~Base that Derived is destroyed before Base.
But why on earth do you think that Base wants to know of Derived? If it's static polymorphism you are after, then the curiously recurring template pattern is what you want:
template <typename T>
class Base {};
class Derived : public Base<Derived> {};
But I don't really think that's what you're aiming at.
Maybe you want a way for Base to communicate with a client and think that should be done with inheritance? If so, then this observer-ish idiom is what you need:
class Client
{
public:
virtual void Behavior() = 0;
protected:
~Client() {}
};
class Base
{
Client& client_;
public:
Base(Client& client) : client_(client) {}
};
class Implementor : public Client
{
public:
Implementor() : Base(*this) {}
virtual void Behavior() { ... }
};
If not even that is what you want, then you need to rethink your design.
I'm actually implementing a generic base class that takes a template parameter class and derives from it, and adds a "safe bool" conversion based on the result of a function call on the derived type. I'd like to avoid using virtual functions, if possible, because I'm a serial premature optimiser I really do care about performance in some of the places I'd like to use this. – Autopulated 37 mins ago
You don't need a reference to the Derived class. Your class is deriving from a template parameter. Just use the common method.
#include <iostream>
template <class T>
class Base : public T
{
public:
bool operator!() const
{
return !this->isOk();
}
};
class TemplateClass
{
public:
bool isOk() const
{
return true;
}
};
int main (int argc, char* argv[])
{
Base<TemplateClass> myClass;
if (!!myClass)
{
std::cout << "ok" << std::endl;
}
else
{
std::cout << "not ok" << std::endl;
}
return 0;
}
You can even use template specialization if you know ahead of time of derived classes that don't implement a common bool check.

C++ Destructor Behavior

I had a question about C++ destructor behavior, more out of curiosity than anything else. I have the following classes:
Base.h
class BaseB;
class BaseA
{
public:
virtual int MethodA(BaseB *param1) = 0;
};
class BaseB
{
};
Imp.h
#include "Base.h"
#include <string>
class BImp;
class AImp : public BaseA
{
public:
AImp();
virtual ~AImp();
private:
AImp(const AImp&);
AImp& operator= (const AImp&);
public:
int MethodA(BaseB *param1) { return MethodA(reinterpret_cast<BImp *>(param1)); }
private:
int MethodA(BImp *param1);
};
class BImp : public BaseB
{
public:
BImp(std::string data1, std::string data2) : m_data1(data1), m_data2(data2) { }
~BImp();
std::string m_data1;
std::string m_data2;
private:
BImp();
BImp(const BImp&);
BImp& operator= (const BImp&);
};
Now, the issue is that with this code, everything works flawlessly. However, when I make the destructor for BImp virtual, on the call to AImp::MethodA, the class BImp seems to have its data (m_data1 and m_data2) uninitialized. I've checked and made sure the contained data is correct at construction time, so I was wondering what the reason behind this could be...
Cheers!
Edit: param1 was actually a reference to B in MethodA. Looks like I over-sanitized my real code a bit too much!
Edit2: Re-arranged the code a bit to show the two different files. Tested that this code compiles, a well. Sorry about that!
If you are casting between related types as you do in this case, you should use static_cast or dynamic_cast, rather than reinterpret_cast, because the compiler may adjust the object pointer value while casting it to a more derived type. The result of reinterpret_cast is undefined in this case, because it just takes the pointer value and pretends it's another object without any regard for object layout.
MethodA takes its parameters by value. This means a copy is passed (and the copy has to be destroyed). That's my best guess for why you might have a BImpl being destroyed that you didn't expect to be, but I don't see what the virtual or non-virtual nature of A's destructor could possibly have to do with it.
But this code can't compile - you use class B in declaring the virtual function in A, but B isn't defined until later. And I don't know what's going on with that cast - you can't reinterpret_cast class types. Perhaps if you work up a test case which demonstrates your issue, and post that?
There's a lot of iffy stuff in this code, so I'm amazed that it works or compiles in any case.
Passing parameters by value instead of reference to MethodA
Casting a B to a BImp via reinterpret_cast -- bad idea! If you're going to cast in that direction, dynamic_cast is the safest.
I fail to see how you're supposed to get a BImp out of a B. You are not invoking any constructors, and you have none that could be invoked that would accept a B. Your default constructor for BImp is private, and assigning a B that has no data, casted to a BImp that still has no data, to a BImp, still isn't going to give you any data!
Several comments:
Your base classes should have virtual destructors so the derived class' dtor is called instead of the just the base class dtor when the object is deleted.
MethodA taking a BaseB pointer as a parameter only to have the pointer reinterpreted as a BImp (a derived class of BaseB) is dangerous. There is no guarantee something else other than BImp is passed to MethodA. What would happen if just a BaseB object was to MethodA? Potentially lots of bad things, I would suspect.
I'm guessing your code "works flawlessly" because you only pass BImp to MethodA. If you are only passing BImp to MethodA then make the signature match the intent (this has the added benefit of removing that awful reinterpret call).
Your code is ill-formed. It is not valid C++. In C++ language reinterpret_cast can only be used to cast between pointer types, reference types, to perform pointer-to-integer conversions (in either direction).
In your code you are trying to use reinterpret_cast to convert from type B to type BImp. This is explicitly illegal in C++. If your compiler allows this code, you have to consult your compiler's documentation in order to determine what's going on.
Other replies already mentioned "slicing". Keep in mind that this is nothing more than just a guess about specific non-standard behavior of your specific compiler. It has nothing to do with C++ language.