7

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

  • I have a struct (Parent) that include a data component (object). This could be a data component of any type - i.e. custom struct too.
  • Only the compiler of the Parent (who created the Parent incl object), and the end receiver needs to know the type of the data component inside the object, as the data is only relevant to them.
  • The Parent struct however might pass through several methods, objects and even to other processes.
  • The data options for the object are limited, and both compiler and decompiler knows the different options of data types.. hence they are able to decompile the object in original form
  • The types however could be extended (i.e. though limited it is not necessarily fixed) and the decompiler and compilers updated in future

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

  • Is this a good solution or may I encounter problems in the future
  • Is there an improvement that could be made on this? That I have not thought about (especially for not including the Object\impl.h?
  • Is there a totally different / better solution?

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
chrisb2244
  • 2,940
  • 22
  • 44
DaClan
  • 329
  • 2
  • 15
  • Is this a duplicate of [_"Why can templates only be implemented in the header file?"_](http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file) at least? – πάντα ῥεῖ Jul 17 '14 at 23:33
  • 1
    Also, it sounds like you've recreated a buggy version of `boost::any`. – Mooing Duck Jul 17 '14 at 23:36
  • Not at all @πάνταῥεῖ - I was looking for an object type in C++ and could not find it. Am trying to see if this is a good general solution or if there might be a better way of implementing it. I have just briefly tested it and it seemed to work. I have not dealt with C++ a lot - there might be a better solution I have not found online – DaClan Jul 17 '14 at 23:36
  • 2
    @DaClan: Generally, we avoid anything remotely like an `object` type. If absolutely necessary (and it pretty much never is), we use `boost::any` – Mooing Duck Jul 17 '14 at 23:38
  • Sorry, I feel stupid to ask, but is this just a kind of wrapper ? What's the goal of this ? – Christophe Jul 17 '14 at 23:38
  • @DaClan [This simple straight forward stuff](http://stackoverflow.com/a/24813864/1413395) might help maybe. – πάντα ῥεῖ Jul 17 '14 at 23:40
  • @Christophe - I guess this is a kind of wrapper. The goal is to store an object in a class that is passed around through several processes / functions. Generally (as I have it) if you don't have object, then the parent need to be template... if it is template then everything that uses it will have to be templated etc etc... goal is to pass a variable from one point to another without changing processes in the middle by templating them - if that make sense – DaClan Jul 17 '14 at 23:42
  • @Mooing Duck- thanks - this is what I was looking for.. I will look into boost::any – DaClan Jul 17 '14 at 23:43
  • Just to add a bit to @Duck s comment: http://www.stroustrup.com/bs_faq2.html#object – Sinkingpoint Jul 17 '14 at 23:45

1 Answers1

7

Generally, we avoid anything remotely like an object type. If absolutely necessary (and it pretty much never is), we use boost::any.

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>() );
Community
  • 1
  • 1
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • wow - you gave me a lot of homework here THANKS!!! Exactly what I was looking for!!! – DaClan Jul 17 '14 at 23:57
  • 2
    A little elaboration on *owning pointers* - those are called smart pointers and are a critical component of [RAII](http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization). I suggest you read up on it. – Qix - MONICA WAS MISTREATED Jul 18 '14 at 00:32