Why can I dynamic_cast to a non-virtual class? - c++

Why does this compile, if A has no virtual functions?
class A {
int a = 42;
};
class B {
void* f() {
return dynamic_cast<A*>(this);
}
virtual void my_virtual() {};
};
Note: Though it makes no sense to write something like this, this was the result of a refactor, after the base class was removed. I feel like there should have been a compiler error.

Because it's not a requirement, and it shouldn't be an error.
Consider the following addition to your classes (after making B::f() public):
class C: public A, public B
{
};
int main()
{
C c;
void* p = c.f();
}
which should, and does, return to p a pointer to the A subobject of c.
Only the conversion source is required to be of polymorphic type, and that is only if it is not known at compile time that the target is a base class of the source.
In the latter case, a decent compiler will not do any conversion at runtime.

Related

virtual function doubts c++

Virtual function d() in the base class A is overidden by a private method in derived class B. When d() is invoked on an instance of B from outside, via a pointer of type A *, it is B::d() that runs, even though it is private to B.
Why does this happen? Shouldn't it be impossible for code outside B to invoke B's private methods?
Demo
#include<iostream>
using namespace std;
class A {
public:
virtual void d(){
cout<<" gfgd ";
}
};
class B :
public A
{
private:
void d(){
cout<<"hytyhtht";
}
};
int main() {
A *a1;
B b;
a1=&b;
a1->d();
return 0;
}
Output:
hytyhtht
The public/protected/private access-rules are enforced at compile-time, not at run-time, which means that they have to rely on logic that the compiler can enforce at compile-time.
In particular, the compiler knows that you are calling the d() method using a A* pointer, and that class A has declared virtual void d() to be a public method, so that means it's okay to call the method.
In general the compiler can't know at compile-time that your pointer is really pointing to a B object, so even if it wanted to it wouldn't be able to flag the call as a compile-time error. (Well, maybe in your particular example it could, but in many cases the compiler doesn't know what the type of the pointer-to object will be, it only knows the type of the pointer)
For example:
// in someotherfile.cpp
void MyFunction(A * a)
{
a->d(); // should this compile, or not?
}

Casting pointer to different pointer causes wrong virtual function to be called

#include <iostream>
struct A {
virtual void a() {
puts("A");
}
};
struct B {
virtual void b() {
puts("B");
}
};
struct C {
virtual void c() {
puts("C");
}
};
struct D : public A, public B, public C {
virtual void c() {
C::c();
puts("cd");
}
};
int main() {
A* obj = new D;
obj->a();
B* b = (B*)obj;
b->b();
C* c = (C*)obj;
c->c();
return 0;
}
I have this code where I have non virtual multiple inheritance. However, it seems to call the wrong virtual function when I call the functions in the main function.
Instead of outputting:
A
B
C
cd
It outputs:
A
A
A
What puzzles me is that when I change the code to doing this:
B* b = (B*)(D*)obj;
b->b();
C* c = (C*)(D*)obj;
c->c();
It outputs what I would expect (see above). Afaik doing a double pointer cast like this wouldn't effect anything and would be optimized out by the compiler. But it seems to be changing what virtual function is being called.
Can someone explain why this would change what virtual function is being called?
Notes:
I printed the pointers at each step, they are the same.
I want to avoid using dynamic_cast (although it does work) as it's too slow for what I need it to do.
Can someone explain why this would change what virtual function is being called?
Generally, a C-style cast between pointer types won't change the value of the pointer and so will have no effect. There is, however, one exception.
A cast between a class and a parent or child class can change the value of the pointer. For example:
class A
{ int a; };
class B
{ int b; };
class C : public A, public B
...
Now, a pointer to an instance of class A will probably have the same value as a pointer to its a member and a pointer to an instance of class B will probably have the same value as a pointer to its b member. A pointer to an instance of class C can't have the same value as a pointer to both its A::a and its B::b members since they're distinct objects.
A function expecting a B* can be passed a C* since a C is a B. Similarly, a function expecting an A* can be passed a C* for the same reason. But at least one of these will require a value change to the pointer.
So casts between these types will change the values, the others are all no-ops.
Of course, all of this is UB. You are casting between unrelated types and then dereferencing them.
I want to avoid using dynamic_cast (although it does work) as it's too slow for what I need it to do.
That seems very hard to believe.

c++ virtual class function returning instance of concrete subclass

What I would like, if not with this syntax, but in spirit :
class A
{
virtual A f()=0;
};
class B : public A
{
B f();
};
I do see the problem with the code above : A is virtual, thus no instance of A can be created, hence no instance of A can be returned.
Yet, concrete subclasses of A (e.g. B) will have to implement the function f, which will always be able to return an instance of themselve (e.g. instance of B), i.e. an instance of a subclass of A.
While the above is incorrect and does not compile, is there a way to get something similar valid ?
Possibly, but not necessarily, of the like:
class A
{
virtual "a concrete sublclass of A" f()=0;
};
note: I prefer not to return a pointer or a reference, as I would prefer B not to have to manage an instance of itself as attribute.
note: if possible c++11, but curious to hear about newer versions as well
Your attempted solution risks object slicing. Copying a B as an A will probably not work the way you expect. In general, it's best to avoid value semantics when dealing with polymorphic types. Consider returning a std::unique_ptr<A> instead :
#include <memory>
class A
{
public:
virtual std::unique_ptr<A> f()=0;
};
class B : public A
{
public:
std::unique_ptr<A> f() override;
};
This requires C++11. It will behave the way you expect and the user won't have to manage the lifetime of the resulting object.
However, contrary to what was shown in the original code, B::foo() won't give you access to the full interface of a B. It's not clear to me if this is required or not. If it is, you will need an extra layer. For example, define a g() that returns std::unique_ptr<B> which f() calls :
class B : public A
{
public:
std::unique_ptr<A> f() override { return g(); }
std::unique_ptr<B> g();
};
It looks like you're trying to write a factory or clone function of sorts. This is commonly done using std::unique_ptr to cleanly pass ownership of the created object to the caller:
class A
{
virtual std::unique_ptr<A> f() = 0;
};
class B : public A
{
std::unique_ptr<A> f() override;
};
Demo
The only downside is that you cannot have B::f return a std::unique_ptr<B> as that's not covariant with std::unique_ptr<A> (even though it implicitly converts to it).
note: if possible c++11, but curious to hear about newer versions as well
No. that is not possible. You can return a covariant type in a derived class though.
If the return type in the base classs is A&, it is ok to return B& in B.
If the return type in the base classs is A*, it is ok to return B* in B.
class A
{
virtual A& f()=0;
virtual A* g()=0;
};
class B : public A
{
B& f();
B* g()=0;
};
Write something like
class A
{
virtual const A& f() const = 0;
};
class B : public A
{
const B& f() const override { return *this; }
};
Instead of reference you may use pointers.

Static assertion that a base pointer "equals" a derived pointer

Suppose I have a polymorphic hierarchy of classes with a common base:
struct Base { ~virtual Base() = default; };
I have inherited a large codebase which contains a long series of accessor functions (one for each derived type) that obtain a derived pointer via reinterpret_cast:
Derived * Get() // Derived inherits from Base
{
Base * b = lookup_derived();
return reinterpret_cast<Derived *>(b);
}
Obviously the code should be using static_cast or dynamic_cast (depending on whether the base is virtual). However, because this translation unit is large and the definitions of all the derived classes are jointly huge, the TU does not contain the definition of Derived, but only its declaration.
I would like to make this code more robust by adding to each derived class definition a static assertion that this reinterpret cast will produce the correct result. Essentially, I want something like this:
struct Derived : Base
{
static_assert(static_cast<Derived *>(std::declval<Base *>()) ==
reinterpret_cast<Derived *>(std::declval<Base *>()));
// ...
};
This constructions does not work of course since declval must not be evaluated, and the result of a reinterpret cast is not a constant expression. Is there any standard C++ mechanism to perform such a test statically? (The alternative would be a runtime check on this in the class constructor.)
Edit: Based on Aaron's post, I struck me that the question could be phrased entirely without reinterpret_casts:
static_cast<void *>(std::declval<Derived *>()) ==
static_cast<void *>(static_cast<Base *>(std::declval<Derived *>()))
I'm not sure if this will be good enough for the setup you have, but this code on ideone works for me (clang 3.5.0 and g++ 4.9.3).
Updated to cast in the other direction, i,e. Derived*-to-Base*, to more closely match the question. And also updated to use static_cast<void*> explicitly instead of C-style casting and reinterpret_cast .
template<typename D, typename B>
struct CheckCasting {
static D d_static;
constexpr
static B* bp = &d_static; // the original object is D,
// that allows us to static_cast both ways
static
constexpr bool static_equals_reinterpret() {
return static_cast<void*>(static_cast<D*>(bp))
== static_cast<void*>( bp );
}
};
struct Base {
constexpr Base() : i(0) {}
int i;
};
struct derived_with_virtual : public Base {
derived_with_virtual() {}
virtual void foo() { }
};
struct without_virtual : public Base {
without_virtual() {}
};
static_assert( ! CheckCasting<derived_with_virtual, Base> :: static_equals_reinterpret() ,"");
static_assert( CheckCasting<without_virtual , Base> :: static_equals_reinterpret() ,"");
A few comments:
I tried to replace the cast to void* with reinterpret_cast, but clang didn't like that. "note: reinterpret_cast is not allowed in a constant expression".
I tried moving the static_assert inside the Derived class without success.
This requires statically allocating an object for each Derived class.

How to downcast from non-polymorphic virtual base class?

Is there a way to downcast from a virtual base class to a derived class when there are no virtual functions involved? Here's some code to demonstrate what I'm talking about:
struct Base1
{
int data;
};
struct Base2
{
char odd_size[9];
};
struct ViBase
{
double value;
};
struct MostDerived : Base1, Base2, virtual ViBase
{
bool ok;
};
void foo(ViBase &v)
{
MostDerived &md = somehow_cast<MostDerived&>(v); //but HOW?
md.ok = true;
}
int main()
{
MostDerived md;
foo(md);
}
Please note that the code is for demonstration only. My real scenario is fairly complex and involves template parameters and casting from one to another, knowing only that the first one is a base of the second one; it can be a normal or virtual base and it may or may not have virtual functions. (See simplified example at the bottom). I can detect the polymorphic case and the virtual/non-virtual base case using type traits, and solve all of them except the non-polymorphic virtual base. So that's what I'm asking about.
I can't really think of a way to do the cast:
Implicit conversions are right out; these only do upcasts.
static_cast is explicitly forbidden for casting from a virtual base class:
5.2.9/2 ... and B is neither a virtual base class of D nor a base class of a virtual base class of D. ...
dynamic_cast can't do it either, as downcasts require a polymorphic class
5.2.7/6 Otherwise, v shall be a pointer to or a glvalue of a polymorphic type (10.3).
10.3/1 ... A class that declares or inherits a virtual function is called a polymorphic class.
reinterpret_cast doesn't apply here at all.
If MostDerived had at least one virtual function, this could of course be solved with dynamic_cast. But when it does not, is there a way to do the cast?
(NOTE All quotes are taken from C++11 draft N3485)
In light of comments focusing on the above example code too much, here's a sketch of what my real situation is:
template <class T_MostDerived>
struct Bar
{
template <class T_Base>
void foo(T_Base &b, typename std::enable_if<std::is_base_of<T_Base, T_MostDerived>::value>::type * = nullptr)
{
T_MostDerived &md = somehow_cast<T_MostDerived>(b);
do_stuff_with(md);
}
};
That is, I know that T_Base is a base class of T_MostDerived (and I know that T_MostDerived is really the most derived type), but I don't know anything else about them; Bar is my code, part of a library, which unknown clients can use. I can detect that it's a non-polymorphic virtual base, but I can't cast it in such case.
There is an implicit unambigious conversion from MostDerived& to its ViBase&. A static_cast can express such a conversion explicitly, and can also do the opposite conversion. That’s the kinds of conversions that static_cast does.
As the OP noted a static_cast down from virtual base is invalid.
The source code below illustrates why:
#include <iostream>
using namespace std;
struct B { virtual ~B(){} };
struct D: virtual B {};
struct E: virtual B {};
struct X: D, E {};
auto main() -> int
{
X x;
B& b = static_cast<E&>( x );
// Can't do the following for the address adjustment that would work for
// D sub-object won't work for E sub-object, yet declarations of D and E
// are identical -- so the address adjustment can't be inferred from that.
//
//static_cast<D&>( b );
// This is OK:
dynamic_cast<D&>( b );
}
Essentially, as this shows, you can't infer the address adjustment from the declaration of D (or E) alone. And neither can the compiler. This also rules out reinterpret_cast.
This requires a hack. A downcast requires math since multiple inheritance may put the base class in some arbitrary position within the derived class. However, if you know the base class is virtually inherited, then there should only be one instance of it in the derived class. This means you can create a conversion function:
struct MostDerived : Base1, Base2, virtual ViBase
{
bool ok;
template <typename T> static MostDerived * somehow_cast (T *v) {
static MostDerived derived;
static T &from = derived;
static size_t delta
= reinterpret_cast<char *>(&from) - reinterpret_cast<char *>(&derived);
char *to = reinterpret_cast<char *>(v);
return reinterpret_cast<MostDerived *>(to - delta);
}
};
What the special C++ casts give you that this function does not is type safety. This function blindly assumes that the passed in ViBase has an appropriate derived child to cast into, which is generally not the case.