Say that I have a void* containing a pointer to an unknown class. I want to use dynamic_cast to do run-time checking on the type of class I actually have. For example:
class Foo {};
void* bar = new Foo;
If I attempt to do dynamic_cast<Foo*>(bar) I get:
'void *': invalid expression type for dynamic_cast
However I need dynamic_cast because in my actual situation I'm not sure that bar is in fact a Foo*.
I've read here that one solution to this is to create a base class for all objects that bar could contain, reinterpret_cast to a pointer to that base class, and then try to dynamic_cast from that object pointer to Foo.
This is difficult for me because the objects that may be stored in bar are not all under my control. (And cause trying to recreate Java gives me heartburn.) Is there another way to do this?
dynamic_cast is use to cast down a polymorphic object to a class that has the type of the object you're trying to cast as it's parent.
void* is completely different from that.
with a pointer to void, you are literally stripping every type information away.
dynamic_cast know that there's a base class and can do type checking through RTTI.
When you cast down a void pointer, you're saying to the compiler: "yeah you know this place in the memory? well, use it as this type" and if the memory is invalid, UB is invoked.
you have three choices here.
Option 1
Use an interface.
Well, a polymorphic base class is the only way to do a dynamic_cast. There is no other way, no hacks, it's the only way. Simple as that.
struct Base { virtual ~Base() = default; };
struct Derived : Base {};
// ...
void test (Base* base) {
auto derived = dynamic_cast<Derived*>(base);
if (derived) {
// derived is valid here.
}
}
Option 2
Identify the type with the pointer
I use a method to have a unique identifier per type and use the identifier to validate the cast. Done without any RTTI
using type_id_t = void(*)();
template <typename T> void type_id() {}
// now we can use a map or a vector.
std::vector<std::pair<type_id_t, void*>> vec;
template<typename T>
void insertToMyVector(T* obj) {
vec.emplace_back(type_id<T>, obj);
}
template<typename T>
T* getObj(int index) {
auto item = vec[index];
return static_cast<T*>(item.first == &type_id<T> ? item.second : nullptr);
}
// ...
int main () {
auto foo = new Foo;
insertToMyVector(foo);
auto maybeFoo = getObj<Foo>(0);
if (maybeFoo) {
// you have a valid Foo here
}
}
Option 3
Generate derived class for any type
This one is quite useful as it can hold any type while keeping type safety. I look like solution 1 but offer more flexibility. The trick it to generate a derived class for any type using templates. The advantage is you can hold any type, but may complexify you cade a bit.
struct Base { virtual ~Base() = default; };
template<typename T>
struct Derived : Base {
Derived(T&& obj) : _obj{std::move(obj)} {}
Derived(const T& obj) : _obj{obj} {}
T& get() {
return _obj;
}
const T& get() const {
return _obj;
}
private:
T _obj;
};
// ...
void test (Base* base) {
auto derived = dynamic_cast<Derived<int>*>(base);
if (derived) {
int i = derived->get();
// derived is valid here, and we can safely access the int
}
}
To ensure dynamic_cast compiles and works, you should create an abstract or interface class with a virtual method.
#include <cassert>
class Bar
{
public:
Bar() = default;
virtual ~Bar() = default;
};
class Foo : public Bar
{
public:
Foo() = default;
virtual ~Foo() = default;
};
int main()
{
Bar* bar = new Foo;
Foo* foo = dynamic_cast<Foo*>(bar);
assert(foo != nullptr);
}
As I understand it you want a polymorphic object but no common base class.
There is already a fairly standard idiom for this - it's called boost::any.
A boost::any carries your object plus some type information. The interface allows you to query the type and to attempt to cast the any to the type you're looking for.
http://www.boost.org/doc/libs/1_59_0/doc/html/any.html
Related
I have some third-party abstract base class
struct foo
{
virtual foo*job() = 0;
...
static void* make_space(size_t sizeofDerived);
};
which I cannot alter. Objects of type foo (and all derived classes) must only be created/constructed using placement-new into the memory returned by foo::make_space(),
because ordinary construction, as in
derived_from_foo z; // or
auto p = new derived_from_foo();
may cause undesired problems (corrupting memory, depending on the compiler, as I found out eventually). So my question: how can I write/design a derived class
struct bar // still abstract, since foo::job() is not provided
: foo
{
...
template<typename Derived, typename...Args>
static Derived* create(Args&&...args)
{
return ::new(foo::make_space(sizeof(Derived)))
Derived(std::forward<Args>(args)...);
}
};
such that construction of objects of type bar or any type derived from bar by any other means than through bar::create() fails at (i) compilation or (ii, less ideal) at run-time?
You can in fact enforce it, at a price.
Consider this class:
class A
{
public:
class Tag
{
public:
Tag(const Tag&) = default;
Tag(Tag&&) = default;
private:
Tag() {}
friend class A;
};
A(Tag, int a, char b) : a(a), b(b) {}
int a;
char b;
template<typename T, typename ... Params>
static T* make(Params&& ... params)
{
return new T(Tag(), std::forward<Params>(params)...);
}
};
Its constructor requires a Tag parameter, but you cannot make a Tag, it's got a private constructor. You can derive from A, but you cannot directly create objects of a derived class either: it needs to pass a Tag to its parent constructor, and you cannot make one.
So the only way to create an object of A or a derived class is by calling A::make.
Well there is still a way to cheat
class B : public A
{
public:
B(Tag t, double q) : A(t, 42, 'z'), q(q) {
// cheating:
B* other = new B(t, 3.14);
}
double q;
};
If this bothers you, you still can enforce correctness at run-time by making Tag non-reusable à la std::unique_ptr. Remove the copy ctor, throw in a private bool flag that you set on construction and clear on move-out, and check it inside make.
I am creating a library which allows the user to store a pointer and later retrieve the pointer.
I have a class which stores the pointer of a generic type.
template <typename generic_type>
class A
{
public:
A() {}
A(generic_type *value) : data(value) {}
generic_type *getData()
{
return data;
}
private:
generic_type *data;
};
I want to also store the instances of these class template in a vector, so i inherited from a base class.
class B
{
};
template <typename generic_type>
class A : public B
{
...
};
class test_class
{
};
std::vector<B *> list;
// -------- example -------
// test_class *test = new test_class();
// list.push_back(new A<test_class>(test));
// list.push_back(new A<test_class>(test));
// list.push_back(new A<test_class>(test));
When retrieving from the list i will get a pointer to base class.
To call the functions in derived class A, it will have to be cast.
// example
B *bp = list.at(0);
A<test_class> *ap = static_cast<A<test_class> *>(bp);
I do not want the user to manually have to cast the base pointer themselves, but be able to call the getData() function in A which will return the actual data based on the generic_type.
// preferred API usage
B *bp = list.at(0); // they will get B pointer in another way but shown here for simplicity
test_class *t = bp->getData();
Looking around for calling child function from parent class, i came upon CRTP, which allowed me to call the function in A;but now i am unable to store it in a vector as B will be templated. So i derived B from another class referencing code from this post.
This allowed me to store it in a vector but i cant seem to find a way to call the function with generic return type and return it.
class C
{
public:
virtual void func() = 0;
};
template <typename derived>
class B : public C
{
public :
void func() // cant change to templated return type as virtual function cant be templated
{
derived *p = static_cast<derived *>(this);
p->getData(); // how to return the value from this ?
}
};
template <typename generic_type>
class A : public B<A<generic_type>>
{
...
};
std::vector<C *> list;
// -------- example -------
// this allows me to do
C *cp = list.at(0);
cp->func(); // will call getData() indirectly
// but am unable to get the returned data
I am not familiar with newer features or design patterns as i have not used c++ for a few years.
Is it possible to get the returned data? or is there a different method or pattern i could use to achieve the desired API usage scenario?
You will never get around the fact that the user has to specify which type they expect to receive. The compiler needs to know at compile-time what the return type of getData will be, so you have to decide at compile-time which concrete A instantiation you are operating on.
However, there is a way to make this "specifying the type" more convenient than a manual static cast: Provide an implicit conversion in B to any pointer.
class B
{
public:
virtual ~B() = default;
template<class T>
operator T*();
};
template <typename generic_type>
class A : public B
{
// ...
};
template<class T>
B::operator T*()
{
A<T>* a = dynamic_cast<A<T>*>(this);
if (!a)
return nullptr;
return a->getData();
}
// Usage:
std::vector<std::unique_ptr<B>> list;
list.emplace_back(new A<test_class>);
list.emplace_back(new A<int>);
list.emplace_back((A<double>*)nullptr);
test_class* out1 = *list[0]; // Returns the correct ptr
test_class* out2 = *list[1]; // Returns nullptr (incorrect type)
double* out3 = *list[2]; // Returns nullptr (data value is null)
https://godbolt.org/z/NT1AF8
This conversion operator assumes that, when we try to convert some object x from a B to some T*, that the dynamic type of x is A<T*>. It attempts the down-cast and returns getData() if it succeeds, or nullptr otherwise.
This works just fine in principle, you should however be aware that implicit conversions are better used sparingly or not at all - they can lead to very surprising behavior. You might also want to (SFINAE-)guard against someone creating an A<A<something>> or A<B>, because that sounds like a headache.
Getting it to work with cv specifiers (i.e. const/volatile) will require some more work (including specifying whether A<const int> should be a thing or not).
You could also take the middle route between manual static_cast and the implicit conversions above by writing a free accessor function like
template<class T>
T* getData(B& b)
{
// See operator T* implementation above.
}
which would be used like double* y = getData<double>(x);. I would prefer this solution for a library interface.
I have the following classes:
class A {
public:
virtual std::string Serialize();
virtual void Deserialize(std::string);
template <typename T>
T* Clone()
{
std::string s = Serialize();
T* t = new T();
t->Deserialize(s);
return t;
}
};
class B : public A {
public:
std::string Serialize() { ... }
void Deserialize(std::string) { ... }
};
Now, if I want to clone B, I do the following:
B b1;
B* b2 = b1.Clone<B>();
Is there any way to remove the template type without re-implementing Clone in each and every derived classes?
I want something like this:
B b1;
B* b2 = b1.Clone();
The way to do this is with CRTP:
class A {
public:
virtual std::string Serialize();
virtual void Deserialize(std::string);
virtual A* Clone() = 0;
};
template <class T>
class HelperA : public A {
T* Clone() override
{
std::string s = Serialize();
T* t = new T();
t->Deserialize(s);
return t;
}
};
class B : public HelperA<B> {
public:
std::string Serialize() { ... }
void Deserialize(std::string) { ... }
};
These 3 level hierarchies are quite common. Basically, the top class is pure interface, as before (note: you should = 0 the other functions too). The middle class uses the CRTP pattern: it is templated on the derived typed. the idea is that by having static access to the derived type, it can automatically implement things like Clone. Then the derived type implements any implementation that cannot be done generically.
Notice that the derived-most type inherits from the CRTP class templated on itself. That's where the name comes from (Curiously Recurring Template Pattern). Of course, since inheritance is transitive B also inherits from A still, as originally, enabling the same sort of things.
Here is a full working example that you can execute: http://coliru.stacked-crooked.com/a/8f2b201a06b5abcc. I kept the code in the answer as similar to the question as possible, but in the coliru example there are a few small but important differences:
usage of owning pointers instead of raw pointers considered good practice in C++, and because smart pointers are not covariant this affects the signatures
correct use of = 0 and override, as well as const
an example of the static downcast which is kind of a signature of CRTP that didn't come up with your example
I have a base class which provides pure virtual interfaces. I need this to store pointers to derived-class objects in a list of pointers to the base class.
The derived class is created using the template mechanism. The problem is now that if I want to have a virtual interface to return a type which is known only to the derived class, I need to pass it as a template argument as well. This is where the dilemma starts...
template <typename ITEM>
class base {
public:
virtual ITEM* get() = 0;
};
template <typename ITEM>
class derived : public base<ITEM>{
public:
ITEM* get() {...};
};
But when using a template in base I need to know this even when creating a list of base pointers:
base* myList[10] = {derived1, derived2,...}
Of course I don't know that type when I define my list. So I need to get rid of the template in my base class somehow.
EDIT: Got rid of this approach because it wasn't a useful approach at all. So no solution for this issue.
The code you write is not valid; there is not a single base type that is then parameterised like in Java, but a number of base<T> types. There is a way to obtain a wrapper for a truly generic object, and it is called "type erasure". It is used, for example in the implementation of boost::any.
Basically, you have a non-template base class with virtual functions, and then you make a template derived class that implements them. Note that the simplified version shown here does not work if you want to have an array of base objects, because base has pure virtual functions and thus cannot be instantiated (and because the T member of the derived type would be sliced off).
struct base;
template<typename T>
struct derived;
struct base {
virtual ~base();
// In this class we don't know about T, so we cannot use it
// Other operations that delegate to the derived class are possible, though
virtual std::size_t sizeofT() const = 0;
virtual const std::type_info& typeofT() const = 0;
// Since all you want is a pointer in "get", you could write it as a void*
virtual void* getPtr() = 0;
// Otherwise, we can implement this template function here that calls the virtual.
// Note that function templates cannot be virtual!
template<typename U>
U& getAs() {
// Verify that the type is the _same_ (no up/downcasts allowed)
// std::bad_cast is thrown here if U is not the same T used to build this object
derived<U>& meAsU = dynamic_cast<derived<U>&>(*this);
return meAsU.obj;
}
};
template<typename T>
struct derived : public base {
T obj;
// A couple of ctors to initialize the object, and the default copy/move ctors/op=
virtual ~derived();
derived(const T& o) : obj(o) {}
derived(T&& o) : obj(std::move(o)) {}
std::size_t sizeofT() const override {
return sizeof(T);
}
const std::type_info& typeofT() const override {
return typeid(T);
}
void* getPtr() override {
return static_cast<void*>(&obj);
}
};
If you want to use the base type directly as a variable, or in an array or container (vector, list, etc.), you need dynamic allocation - there are no two ways around it. You have two choices, which differ on where to place the responsibility for the dynamic allocation:
You can use the solution above if you limit yourself to having arrays of pointers to base. E.g. an array of std::unique_ptr<base>. The pointed-to objects would be of type derived<something>.
base err1; // Error, abstract class (what would it contain?)
base err2 = derived<int>(2); // Still abstract class, and the int would be sliced off
std::unique_ptr<base> ok(new derived<int>(3)); // Works
std::vector<std::unique_ptr<base>> objects;
objects.push_back(std::make_unique(new derived<int>(5)));
objects.push_back(std::make_unique(new derived<std::string>(2)));
int& a = objects[0].getAs<int>(); // works
std::string& b = objects[1].getAs<std::string>(); // works too
std::string& bad = objects[1].getAs<double>(); // exception thrown
Otherwise, you would have to implement the dynamic allocation in the base/derived classes themselves. This is what classes like boost::any or std::function do. The simplest any object would simply be a wrapper of an unique-ptr of the base class I showed here, with appropriate implementations of operators, etc. Then, you can have a variable of type any x = y; and the class would, inside its constructor, do the required new derived<Y>(y) required.
I'd like to cast a base class pointer to a derived one in order to take advantage of some methods unique to the derived class. Here's an Ideone of a simple example that works:
template<typename A>
class Base {};
template<typename A, typename B>
class Derived : public Base<A> {
public:
void doSomething() {}
};
int main() {
Base<int>* foo = new Derived<int, double>;
static_cast<Derived<int, double>*>(foo)->doSomething();
return 0;
}
Now, the problem is that my foo is actually a member of a templated class,
template<typename A>
class Container
{
public:
Base<A>* foo;
};
and at the time I cast, I don't know what A is:
int main() {
Container<int> container;
container.foo = new Derived<int, double>;
// a lot of code later...
static_cast<Derived< /* ??? */ , double>*>(container.foo)->doSomething();
return 0;
}
Then I thought this might be possible if I could somehow store what A is in my base class, like
template<typename A>
class Base
{
public:
static type template_type = A; // made-up syntax
};
so that I can refer to it like
static_cast<Derived<container.template_type, double>*>(container.foo)->doSomething();
but according to this question it's not possible to store types in C++.
How do I achieve this cast without knowing A?
That is, how do I cast a specialized base pointer to a derived pointer that specializes on an additional template parameter? In less technical terms, I just want to take a Base pointer and tack on the other specialization necessary to form the Derived pointer.
Usually it is not wise to do an up-cast and there is usually a better design that you may use to avoid the need of up-cast at all, but if you really need it, then you may use dynamic_cast to do this.
this operator try to convert from one type to another type dynamically and if conversion is not possible, it will return nullptr. But remember that it only work for polymorphic types(types that have at least one virtual function) so in this case your Base class must be polymorphic(since you are holding a pointer to base class, you possibly need a virtual destructor to allow delete to work on base pointer and this make Base a polymorphic class).
But to remember a type in C++, you have 2 options:
Use typedef:
You may use typedef to hold type information in the class:
template< class A >
class my_class
{
public:
typedef A input_type;
};
template< class T >
void do_something(T const& t)
{
typename T::input_type n;
do_something_on_input_type(n); // possibly overloaded for different input types
}
this approach is really fast and have no overhead in runtime, but you can use it only in cases when you want to do something in compile time. and if the type of pointer is not determined until runtime this approach is not useful.
Use std::type_info
Using this you can actually hold type information with the class:
class Base { virtual std::type_info const& get_type() const = 0; };
class Child : public Base
{
virtual std::type_info const& get_type() const { return typeid(Child);
void child_specific_function() { /**/ }
}
class ChildOfChild : public Child
{
virtual std::type_info const& get_type() const { return typeid(ChildOfChild); }
// ...
};
void do_something(Base* base)
{
if (base->get_type() == typeid(Child))
{
static_cast<Child*>(base)->child_specific_function();
}
}
This sound really interesting but, it is only useful when you know exact type of the object and it does not work for derived types, so this approach work for Child but not for ChildOfChild