Having programmed mostly in C# I find myself in a loss when it comes to C++. I however need to create a C++ app, as it is merely a component in a bigger C++ solution.
Situation
Problem - I do not want to recreate each method and object that might encounter this data component with a "template"... also seeing that the data type could in future be altered suggested that templates for each process that encounter the object in the long run is not ideal to start with.
I was looking for something similar to C# Object - and have written the following components
Question
The Code
I have the following in my Header file
struct Object
{
Object();
// Return true if value has succesfully been set
// Return false if there is no compatibility between Value and result.
template <typename T>
bool GetValue(T &result);
template<typename T>
bool SetValue(T value);
virtual LPVOID GetObjectAddress() = 0;
virtual const char* GetType() = 0;
};
template<typename T>
struct ObjectType:public Object
{
ObjectType(T value);
T Value;
LPVOID GetObjectAddress();
const char* GetType();
};
I also have have a CreateType function for creating several ready made objects at start and for example purposes is called as follows at end of .h file
template class CreateType<int>;
Bear in mind the int is just for example... it is actually different structs.
I also have another header file which is included at the bottom of this header file as follows:
#include "Implementation\Object_impl.h"
-> looks like this
template<typename T>
ObjectType<T>::ObjectType(T value)
{
Value = value;
};
template <typename T>
// Return true if value has succesfully been set
// Return false if there is no compatibility between Value and result.
bool Object::GetValue(T &result)
{
if (typeid(result).name() == GetType())
{
result = *(T *)GetObjectAddress();
return true;
}
return false;
};
template<typename T>
bool Object::SetValue(T value)
{
if (typeid(T).name() == GetType())
{
*(T*)GetObjectAddress() = value;
return true;
}
return false;
};
template<typename T>
const char* ObjectType<T>::GetType()
{
return typeid(Value).name();
}
template<typename T>
EXPOBJ LPVOID ObjectType<T>::GetObjectAddress(){
return (LPVOID)&Value;
}
I wish I could include most of this in a cpp file, but then I would not be able to create different object on demand... I am not yet sure what the implications would be... also to extend the types one only need to include the normal object header file.
I know inline could be an option, but also think it is not ideal?
At the moment however this compiles and works perfectly as a "generic" option. One could also extend by inheriting from inheriting from "Object"?
...oh and to use I just do this - which seemed to work:
Object * a;
a = new ObjectType<testing>(testing());
testing x = testing();
x.i = 50;
a->SetValue(x);
testing y = testing();
testing &z = y;
a->GetValue(z);
cout << z.i << " for z and y = " << y.i << endl;
Result -> 50 for z and y = 50
As to your code: that's actually impressively good, but here's bits I'd mention:
You have no destructor. That's a MAJOR bug.
virtual ~Object() {}
//and
virtual ~ObjectType() {}
Also, GetObjectAddress
is not type-safe.
class Object {
//stuff
template<class T>
T* GetObjectAddress();
private:
virtual LPVOID GetRawPointer() = 0;
};
template<class T>
inline T* Object::GetObjectAddress()
{
if (typeid(T).name() == GetType() || typeid(T).name()==typeid(void).name())
{
return static_cast<T*>(GetRawPointer());
}
return nullptr;
}
Also, I would ban the copy and move assignment bits, which helps prevents errors.
class Object {
Object(const Object&) = delete;
Object(Object&&) = delete;
Object& operator=(const Object&) = delete;
Object& operator=(Object&&) = delete;
//stuff
};
I would give the derived type a default constructor, and conversion constructors
template<typename T>
struct ObjectType:public Object
{
ObjectType() {}
//C++11 here:
template<class...Ts>
ObjectType(Ts...Vs)
:Value(std::forward<Ts>(Vs)...) {}
//C++03 here:
template<class first>
ObjectType(const first& f) : Value(f) {}
template<class t0, class t1>
ObjectType(const t0& p0, const t1& p1) : Value(p0, p1) {}
template<class t0, class t1, class t2>
ObjectType(const t0& p0, const t1& p1, const t2& p2) : Value(p0, p1, p2) {}
//etc etc etc
Finally, use smart pointers instead of raw owning pointers. Raw pointers are fine, as long as they don't own the thing they point at.
std::unique_ptr<Object> a;
a.reset( new ObjectType<testing>() );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With