Component Type Copy Constructor Problem

closed account (oGhfSL3A)
Hello! Thanks for taking the time to read this.

I am writing a component – entity system for a small game, where entities are represented by id numbers in the components(which are objects).
In the real code there are different systems for each type of component, and each system would loop through a container of all the components it stores, but to illustrate my problem there is just one system that stores one component.
My problem is that I have the need for multiple types of the same sort of component. For example, I have a graphics system that loops through all graphical components and updates them, but some graphical components want to be represented by a sprite (I'm using SFML: sf::sprite) and others want to be represented by a solid colour (sf::RectangleShape). In the future I might also want a component that has multiple sprites.
I cant use polymorphism because the systems access their components directly rather than through a pointer. The way around this I have been trying is to give the component a type object, which would have all of the specific functionality of this type of component.
Now, because systems get their components from copies, I gave component a deep copy constructor to create a new type object for the new copy, but I cant get it to work.

I haven't actually needed to use copy constructors for anything before, so my guess is that's where I've messed up.

Please help :(

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <iostream>

class cType{                     //component type
public:
    virtual ~cType(){}
    virtual void doSomething(){}
    virtual cType* clone()=0;
};

class ctSpecific: public cType{         //specific component type
private:
    unsigned somenumber_;               //just some specific data
public:
    ctSpecific(){
        somenumber_=8;
    }
    virtual ~ctSpecific(){}
    virtual void doSomething(){
        std::cout << "I have number "<< somenumber_ <<".\n";
    }
    virtual cType* clone(){
        return new ctSpecific(*this);
    }
};

class component{
public:
    cType* type_;
    component(){}
    component(const component &original){
        type_= original.type_->clone();
    }
    ~component(){
        delete type_;
    }
    void setType(cType* t){
        type_=t->clone();
    }
    void use(){
        type_->doSomething();
    }
};

class system{
    component component_;               //i want to avoid turning this into a pointer
public:
    void addComponent(component c){
        component_=c;
    }
    void update(){
        component_.use();
    }

};

int main(){
    component oComponent;
    ctSpecific oComponentType;
    oComponent.setType(&oComponentType);    //component should have its own copy of its type now

    system oSystem;
    oSystem.addComponent(oComponent);       //component copy constructor gets called
    oSystem.update();                       //system should get its own component with its own type, that can be used(), which will doSomething()? right?
    return 0;                               //it doesnt :(
}
closed account (SECMoG1T)
I really am not sure but this

1
2
virtual cType* clone(){
        return new ctSpecific(*this);}///returning a local pointer *?&^% 


why not just return a copy of *this instead , wait i might be wrong though.
Last edited on
Because of line 48, You need operator= for component. Since you didn't provide one, the compiler has synthesized a shallow copy one for you.

Also, type_ is going to turn into a nightmare, it should be initialised in the constructor (and released in the destructor). That 2-stage initialisation is going to come back and bite you in the leg one day.

1
2
3
4
5
6
7
8
component & operator=(const component &rhs)
{
   if (&rhs == this) return *this;
   *type_ = *rhs.type_; // this is another reason why type_ should be created in constructor, it may not be initialised here, and how can we tell?
   return *this;
}

component() : type_(new ctSpecific) {} // e.g. 
Last edited on
closed account (oGhfSL3A)
Yes, that's it. Thanks!
Turns out I don't need the operator overload In the actual code since component actually has a vector - but at least I just learned what they are.

Also, I cant initialise type_ in component's constructor, since component only knows it has a cType (there's more than one specific type in the actual code), it doesn't know its specific type.

I can pass it's type into the constructor though, which is a bit better, I think:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
class component{
public:
    cType* type_;
    component(cType* t){
        type_=t->clone();
    }
    component(const component &original){
        type_= original.type_->clone();
    }
    ~component(){
        delete type_;
    }
    void use(){
        if(type_){
            type_->doSomething();
        }
    }
};

class gSystem{
    std::vector<component> components_;
public:
    gSystem(){}
    void addComponent(component c){
        components_.push_back(c);
    }
    void update(){
        for(unsigned i=0; i<components_.size(); i++){
            components_[i].use();
        }
    }
};

int main(){
    ctSpecific oComponentType;
    component oComponent(&oComponentType);

    gSystem oSystem;
    oSystem.addComponent(oComponent);
    oSystem.update();
    return 0;                               //works (:
}
Topic archived. No new replies allowed.