I have following classes.
class A
{
public:
void fun();
}
class B: public A
{
}
class C: public A
{
}
A * ptr = new C;
Is it ok to do something like below? Will i have some problems if introduce some virtual functions in the baseclass?
((B *)ptr)->fun();
This may look stupid, but i have a function that calls A's function through B and i don't want to change that.
You can't cast an A* pointing to Class C as a B* because Class C doesn't have any relation with Class B. You'll get undefined behavior which will probably be the wrong function called and stack corruption.
If you intended for class C to derive from class B then you could. However, you wouldn't need to. If class C doesn't have fun() defined, it will inherit A's. You didn't declare fun() virtual though so you'll get strange behavior if you even implement C::fun() or B::fun(). You almost certainly want fun() to be declared virtual.
I'm guessing here but I suspect the behavior of this might depend on the compiler you use and how it decides to organize the vf pointer table.
I'm also going to note that I think what you are doing is a bad idea and could lead to all kinds of nightmarish problems (use of things like static_cast and dynamic_cast are generally a good idea). The other thing is because fun() is defined in the base class (and it is not virtual) ptr->fun() will always call A::fun() without having to cast it to B*.
You don't have to do the casting (B*) ptr->fun(); since the fun() is already in the base class. both objects of class B or C will invoke the same fun() function in your example.
I'm not sure what happens when u override the fun() function in class B...
But trying to invoke function from another class (not the base class) is bad OO, in my opinion.
You can cast from A * to B *, and it should work if the original pointer was B *.
A* p = new B;
B* q = static_cast<B*>(p); // Just work (tm)
But in this case it is a C *, and it is not guaranteed to work, you will end with a dangling pointer, if you are lucky you will get an access violation, if not you man end up silently corrupting your memory.
A* p = new C;
B* q = static_cast<B*>(p); // Owned (tm)
Related
I mean the following. I have a few classes which inherit the same base class. Union consists of pointers of these classes:
#include "stdio.h"
class A {
public:
A() { printf("A\n"); }
virtual ~A() { printf("~A\n"); }
};
class B : public A {
public:
B() { printf("B\n"); }
virtual ~B() { printf("~B\n"); }
};
class C : public A {
public:
C() { printf("C\n"); }
virtual ~C() { printf("~C\n"); }
};
int main() {
union {
B* b;
C* c;
} choice;
choice.b = new B();
delete choice.c; //We have B object, but deleting C
return 0;
}
It seems to work, but I'm not sure if it isn't implementation-specific behaviour. Can I use such weird deleting method or should I remember a type of stored object and delete it respectively?
P.S. I use C++11 and want it works on both GCC and Visual C++ (2012 and higher). In a real project I have more complex class hierarchy but all of them are successors (directly or indirectly) of the same abstract base class
This is a double dose of undefined behavior. First, you can't delete a B through a pointer to C. ยง5.3.5 [expr.delete]/p3:
In the first alternative (delete object), if the static type of the
object to be deleted is different from its dynamic type, the static
type shall be a base class of the dynamic type of the object to be
deleted and the static type shall have a virtual destructor or the
behavior is undefined. In the second alternative (delete array) if the
dynamic type of the object to be deleted differs from its static type,
the behavior is undefined.
Second, accessing the inactive member of a union is also undefined behavior in C++.
There's no need to use an union here anyway. B and C share the same base class, so you can just store the pointer in an A *.
You shouldn't. You are only allowed to read from the union member you last wrote into and you're only allowed to delete an object through a pointer to a base class (if it has a virtual destructor). It may seem to work now, but you may find it to break randomly in the future, usually due to an aggressive optimizer.
Why don't you store a pointer to A instead of the union?
As it has been said in other answer, this is not proper C++.
My impression is that you want to keep an union of pointers because in certain circumstances you need an instance of a (sub)class of B, and in another an instance of C, with the issue of B and C having not quite the same interface. Perhaps you store several of these in a container, or simply you don't know until runtime which instance will be used.
So you may keep your code as it was, with perhaps a type tag somewhere indicating which instance has been created, and then use a switch each time you need to determine the correct code to run, or you could leverage your classes to actually invoke the proper function at run time, by including in the common base class of B and C(1) a virtual method, and overload this method in B and C with the proper branch of the switch, then replace the union with a simple pointer to the base class.
(1) that base class doesn't have to be A: if you don't want to clutter your class tree, just make a different class having the minimal interface needed there, and thanks to C++ multiple inheritance, have B and C inherit from it as well. Don't forget the virtual destructor!
For me this case looks legit and there is no undefined behaviour.
He is using type-punning and it is legit because it B* b and C* c in union members is a pointers and could be converted to char array.
Both B and C have virtual destructor because of base class (not because base is a same! but because base have virtual destructor).
12.4.9 If a class has a base class with a virtual destructor, its destructor (whether user- or implicitly-declared) is virtual.
While destructor call, (because it is virtual) exact function address will be picked up from choice variable and proper destructor sequence will be called. So there is no ANY undefined behaviour at all.
I have a C++ lib that makes use of a object hierarchy like this:
class A { ... }
class B : public A { ... }
class C : public A { ... }
I expose functionality through a C API via typedefs and functions, like this:
#ifdef __cplusplus
typedef A* APtr;
#else
typedef struct A* APtr;
#endif
extern "C" void some_function(APtr obj);
However, say a use of the C API does something like this:
BPtr b = bptr_create();
some_function((APtr) b);
This is polymorphically valid, since B extends A, and my API depends on such functionality being possible, but I want to make sure that this will still interoperate properly with the C++ code, even if B overrides some of A's virtual methods.
More importantly, why or why not? How can C++ identify at runtime that the obj parameter of some_function is actually a pointer to B, and therefore call its overridden virtual methods instead?
The C code is not valid (nor would the equivalent C++ code in a context where the class definition is not visible) because what C does in this case is the equivalent of a reinterpret_cast. Note that in a simple situation like yours it will likely "work" because most compilers will put the single base object at the beginning of the derived object, so a pointer adjustment is not necessary. However, in the general case (especially when using multiple inheritance), the pointer will have to be adjusted to point to the correct subobject, and since C does not know how to do that, the cast is wrong.
So what is meant with "pointer adjustment"? Consider the following situation:
class A { virtual ~A(); int i; ... };
class B { virtual ~B(); int j; ... };
class C: public A, public B { ... };
Now the layout of C may be as follows:
+----------------------------+----------------------------+
| A subobject (containing i) | B subobject (containing j) |
+----------------------------+----------------------------+
where the virtual pointers of both the A and B subobjects point to C.
Now imagine you've got a C* which you want to convert to a B*. Of course the code which receives the B* may not know about the existence of C; indeed, it may have been compiled before C was even written. Therefore the B* must point to the B subobject of the C object. In other words, on conversion from C* to B*, the size of the A subobject has to be added to the address stored into the pointer. If you do not do this, the B* will actually point to the A subobject, which clearly is wrong.
Now without access to the class definition of C, there's of course no way to know that there even is an A subobject, not to mention how large it is. Therefore it is impossible to do a correct conversion from C* to B* if the class definition of C is not available.
C++ uses the virtual function table which is in memory per class ,
and when an object is created of that particular derived class its
virtual table decides which function gets called.
So its bit c++ compile time Plus Runtime magic :)
http://en.wikipedia.org/wiki/Virtual_method_table
Short answer: Yes this will work.
Why: since A and some_function is implemented in C++, all virtual function calls will occur in C++ code as usual, where the class definition is included, and there is nothing magic about it. In C code only opaque pointers are passed around, and C code never will be able to call the virtual functions directly, because it never could compile the definition of A.
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.
# include <iostream>
using namespace std;
class A
{
public:
virtual void f()
{
cout << "A::f()" << endl;
}
};
class B:public A
{
private:
virtual void f()
{
cout << "B::f()" << endl;
}
};
int main()
{
A *ptr = new B;
ptr->f();
return 0;
}
This code works correctly and prints B::f(). I know how it works, but why is this code allowed?
Access control is performed at compile time, not runtime. There's no way in general for the call to f() to know the runtime type of the object pointed to by ptr, so there's no check on the derived class's access specifiers. That's why the call is permitted.
As for why class B is permitted to override using a private function at all - I'm not sure. Certainly B violates the interface implied by its inheritance from A, but in general the C++ language doesn't always enforce inheritance of interface, so the fact that it's Just Plain Wrong doesn't mean C++ will stop you.
So I'd guess that there's probably some use case for this class B - substitution still works with dynamic polymorphism, but statically B is not a substitute for A (e.g. there can be templates that call f, that would work with A as argument but not with B as argument). There may be situations where that's exactly what you want. Of course it could just be an unintended consequence of some other consideration.
This code is allowed because f is public in A's interface. A derived class cannot change the interface of a base class. (Overriding a virtual method isn't changing the interface, nor is hiding members of a base, though both can appear to do so.) If a derived class could change a base's interface, it would violate the "is a" relationship.
If the designers of A want to make f inaccessible, then it should be marked protected or private.
Your base class is defining the interface for all the inherited children. I do not see why it should prevent the mentioned access. You can try deriving a class down from 'B' and use the Base interface to call , which would result in an error.
Cheers!
In addition to Steve's answer:
B is publically derived from A. That implies Liskov substitutability
Overriding f to be private seems to violate that principle, but actually it does not necessarily - you can still use B as an A without the code getting in the way, so if the private implementation of f is still okay for B, no issues
You might want to use this pattern is B should be Liskov substitutable for A, but B is also the root of another hierachy that is not really related (in Liskov-substitutable fashion) to A, where f is no longer part of the public interface. In other words, a class C derived from B, used through a pointer-to-B, would hide f.
However, this is actually quite unlikely, and it would probably have been a better idea to derive B from A privately or protected
Function access control check happens in later stage of a c++ function call.
The order in high level would be like name lookup, template argument deduction(if any), overload resolution, then access control(public/protect/private) check.
But in your snippet, you were using a pointer to base class and function f() in base class is indeed public, that's as far as compiler can see at compiler time, so compiler will certain let your snippet pass.
A *ptr = new B;
ptr->f();
But all those above are happens at compile time so they are really static. While virtual function call often powered by vtable & vpointer are dynamic stuff which happens at runtime, so virtual function call is orthogonal to access control(virtual function call happens after access control),that's why the call to f() actually ended B::f() regardless is access control is private.
But if you try to use
B* ptr = new B;
ptr->f()
This will not pass despite the vpointer & vtable, compiler will not allow it to compile at compile time.
But if you try:
B* ptr = new B;
((static_cast<A*>(ptr))->f();
This would work just fine.
Pretty much like in Java, in C++ you can increase the visibility of methods but not decrease it.
Consider this simple situation:
A.h
class A {
public:
virtual void a() = 0;
};
B.h
#include <iostream>
class B {
public:
virtual void b() {std::cout << "b()." << std::endl;};
};
C.h
#include "A.h"
#include "B.h"
class C : public B, public A {
public:
void a() {std::cout << "a() in C." << std::endl;};
};
int main() {
B* b = new C();
((A*) b)->a(); // Output: b().
A* a = new C();
a->a(); // Output:: a() in C.
return 0;
}
In other words:
- A is a pure virtual class.
- B is a class with no super class and one non-pure virtual function.
- C is a subclass of A and B and overrides A's pure virtual function.
What surprises me is the first output i.e.
((A*) b)->a(); // Output: b().
Although I call a() in the code, b() is invoked. My guess is that it is related to the fact that the variable b is a pointer to class B which is not a subclass of class A. But still the runtime type is a pointer to a C instance.
What is the exact C++ rule to explain this, from a Java point of view, weird behaviour?
You are unconditionally casting b to an A* using a C-style cast. The Compiler doesn't stop you from doing this; you said it's an A* so it's an A*. So it treats the memory it points to like an instance of A. Since a() is the first method listed in A's vtable and b() is the first method listed in B's vtable, when you call a() on an object that is really a B, you get b().
You're getting lucky that the object layout is similar. This is not guaranteed to be the case.
First, you shouldn't use C-style casts. You should use C++ casting operators which have more safety (though you can still shoot yourself in the foot, so read the docs carefully).
Second, you shouldn't rely on this sort of behavior, unless you use dynamic_cast<>.
Don't use a C-style cast when casting across a multiple inheritance tree. If you use dynamic_cast instead you get the expected result:
B* b = new C();
dynamic_cast<A*>(b)->a();
You are starting with a B* and casting it to A*. Since the two are unrelated, you're delving into the sphere of undefined behavior.
((A*) b) is an explicit c-style cast, which is allowed no matter what the types pointed to are. However, if you try to dereference this pointer, it will be either a runtime error or unpredictable behavior. This is an instance of the latter. The output you observed is by no means safe or guaranteed.
A and B are no related to each other by means of inheritance, which means that a pointer to B cannot be transformed into a pointer to A by means of either upcast or downcast.
Since A and B are two different bases of C, what you are trying to do here is called a cross-cast. The only cast in C++ language that can perform a cross-cast is dynamic_cast. This is what you have to use in this case in case you really need it (do you?)
B* b = new C();
A* a = dynamic_cast<A*>(b);
assert(a != NULL);
a->a();
The following line is a reinterpret_cast, which points at the same memory but "pretends" it is a different kind of object:
((A*) b)->a();
What you really want is a dynamic_cast, which checks what kind of object b really is and adjust what location in memory to point to:
dynamic_cast<A*>(b)->a()
As jeffamaphone mentioned, the similar layout of the two classes is what causes the wrong function to be called.
There is almost never an occasion in C++ where using a C-style cast (or its C++ equivalent reinterpret_cast<>) is justified or required. Whenever you find yourself tempted to use one of the two, suspect your code and/or your design.
I think you have a subtle bug in casting from B* to A*, and the behaviour is undefined. Avoid using C-style casts and prefer the C++ casts - in this case dynamic_cast. Due to the way your compiler has laid out the storage for the data types and vtable entries, you've ended up finding the address of a different function.