Init parent's member that cannot be passed to constructor

I have many classes inheriting each other, like A, B::A, C::B.
All of them must have an index that is never modified after object creation, and cannot be given different other than defined in the module in which it is defined.
It means that
class constructor cannot have this index as a parameter,
so I cannot simply do it through constructor inheritance.
Meanwhile, index is private, as it must not be modified.

I found a way though.
EDIT: WHAT IS WRITTEN BELOW FAILED, DOES NOT WORK.
I make such constructor for the parent's class:
1
2
TObject::TObject() : _typeIndex(-1) {
}

Then I gave the parent class an init method like this:
1
2
3
4
5
6
7
8
        inline void initTypeIndex(int typeIndex) {
            if (_typeIndex == -1)
                _typeIndex = typeIndex;
        #if SAFE_MODE
            else
                ShowError("ERROR");
        #endif
        };

Then a child class have a constructor like this:
1
2
3
4
TDummy::TDummy(TObject* baseObject, int orderIndex) :
               TComponent(baseObject, orderIndex) {
               initTypeIndex(OBJECT_TYPE_DUMMY);
}

OBJECT_TYPE_DUMMY is an automatically generated value that is always >= 0.
So there is no possibility other than index gets OBJECT_TYPE_DUMMY value and then never changes, as the variable itself is private and init method works only once, at constructor.
Last edited on
and cannot be given different other than defined in the module in which it is defined.

Huh?

Am I missing some better (I mean like, you don't have to set temporare value, as it's few microseconds run-time :]]]]]]), simpler solution?

What's the chance to have it optimized by compiler btw?

I assume by temporary value that you mean OBJECT_TYPE_DUMMY. Why would you want to optimize two integer assignments and one function call? Which only happens once for every constructor that has the initTypeIndex call.
Sometimes you have to pick your battles when it comes to optimization.
Last edited on
If I follow your (very incomplete) code snippets correctly, it sounds like TDummy derives from TComponent, which derives from TObject. In addition, TComponent takes a pointer to a separate TObject object as a constructor argument (baseObject). Nothing about this convinces me that the _typeIndex value cannot be set during construction. Why can't you just pass OBJECT_TYPE_DUMMY to the TComponent constructor in the TDummy constructor?

doug4, TDummy : TComponent : TObject.
_typeIndex cannot be set during construction because _typeIndex is private. Neither TComponent or TDummy or any of their childs should not access _typeIndex, but just read-only reference typeIndex.
_typeIndex can be changed, but only by TObject itself. That is what I need.
I cannot pass OBJECT_TYPE_DUMMY as a parameter because I would have a constructor that can set _typeIndex. No one should be able to set _typeIndex other than it is automatically generated, that's why such constructor shouldn't exist. (I don't wanna make such interface that easily crashes my prog)

kevinkjt2000, I mean, -1 is temporary value since TObject init until TDummy assignment.

BTW, what I have done does not work. :[
I just noticed that I assign typeIndex for only first child class, then all consequent constructors simply do nothing with _typeIndex. (Works only for single inheritance)
Last edited on
I cannot pass OBJECT_TYPE_DUMMY as a parameter because I would have a constructor that can set _typeIndex. No one should be able to set _typeIndex other than it is automatically generated, that's why such constructor shouldn't exist. (I don't wanna make such interface that easily crashes my prog)


However, you immediately call initTypeIndex from within the TDummy constructor. How is that any different from passing a typeIndex value as a constructor argument? You can still pass OBJECT_TYPE_DUMMY as a constructor argument. The value can still be private and inaccessible by the derived classes. There is no need for any setters or getters of the value (like initTypeIndex). You can even make the value const, so it never gets changed at all.


No one should be able to set _typeIndex other than it is automatically generated,
How does constructing and setting _typeIndex with a function call solve this problem? It doesn't. Actually, someone could create a subclass that constructs the base class and does not call initTypeIndex. At that point, the object could have _typeIndex initialized to anything, ruining your scheme.

There is no way to guarantee that the _typeIndex field of TObject is always initialized with a proper value. In any case you need to pass a valid value from the derived class either in the constructor or in an initTypeIndex function. In the constructor the derived class would generate the _typeIndex value, so it is never visible to the user. If you make the constructor protected, a base class object cannot be constructed, only a subclass object. What I'm suggesting is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class TObject
{
protected:
    TObject(int typeIndex /*, other args */) : _typeIndex(typeIndex) {}
private:
    int _typeIndex;
};

class TComponent : public TObject
{
protected:
    TComponent(int typeIndex /*, other args */) : TObject(typeIndex /*, other args*/) {}
};

class TDummy : public TComponent
{
public:
    TDummy(/* args */) : TComponent(OBJECT_TYPE_DUMMY /*, other args */) {}
};

Notice, only the TDummy constructor is public, so TObject cannot be initialized by anything other than the automatically generated value from the TDummy constructor. If an intermediate class (like TComponent) is to be concrete as well as a parent to a further class, it can have a public constructor that generates its own type index as well as the protected constructor that I show.
I am still confused about what you want to accomplish. Hopefully this example fits your situation.
There really is no reason that you can't call parent constructors
http://ideone.com/4XCUb2
There comes a point where your classes need to trust each other. You want objects derived from TObject to ensure have different values for _typeIndex, but don't want to provide a way for them to do it.

This is what protected members are for. Just make _typeIndex protected and have the derived classes set it. Or give each derived class a protected constructor that includes the _typeIndexvalue and pass them down the line the way doug4 showed.


Thank you all.
It seems impossible to do as I want. I will go protected constructor indeed... :[
I applied some macroses to make less repetitive code.
Now it has repetitive code, but it's better organized imo.
Do you share my opinion or this looks more like a joke? )))

(Letter T means Type, C - Constructor,
IM_ARGS(), IM_VALS() - ARGS, VALS for intermediate (protected) constructor)
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
66
67
68
69
70
71
72
73
74
#ifndef KENG_OBJ_TYPES_FRAME_HPP_INCLUDED
#define KENG_OBJ_TYPES_FRAME_HPP_INCLUDED

#include "../main/obj_basic_types.hpp"
#include "../main/obj_type_index.hpp"

#define TFRAME_INDEX UNIQUE_OBJ_TYPE_INDEX

#define CFRAME_DEFS\
        TObject* baseObject = 0,\
        unsigned orderSize = 30,\
        int boundRight = 0,\
        int boundBottom = 0,\
        int startX = 0,\
        int startY = 0

#define CFRAME_ARGS\
        TObject* baseObject,\
        unsigned orderSize,\
        int boundRight,\
        int boundBottom,\
        int startX,\
        int startY

#define CFRAME_VALS\
        baseObject,\
        orderSize,\
        boundRight,\
        boundBottom,\
        startX,\
        startY

namespace Keng {

class TFrame : public TBasis {
    private:
        virtual void update();

    protected:
        int _boundRight;
        int _boundBottom;

        int _x;
        int _y;

        TFrame(IM_ARGS(CFRAME_ARGS));

    public:
        int const& boundRight = _boundRight;
        int const& boundBottom = _boundBottom;

        int const& x = _x;
        int const& y = _y;

        TFrame(CFRAME_DEFS);

        virtual void setX(int x);
        virtual void setY(int y);
};

inline TFrame::TFrame(IM_ARGS(CFRAME_ARGS)) : TBasis(IM_VALS(CBASIS_VALS)) {
    _boundRight = boundRight;
    _boundBottom = boundBottom;

    _x = startX;
    _y = startY;
};

inline TFrame::TFrame(CFRAME_ARGS) : TFrame(IM_VALS(CFRAME_VALS)) {
};

}

#endif // KENG_OBJ_TYPES_FRAME_HPP_INCLUDED 

Inline here isn't meant to actually inline anything.

Edit:
https://github.com/trueKrogoth/keng/blob/master/obj_types/frame.hpp
Last edited on
> It seems impossible to do as I want.
¿what do you want to do?

> I applied some macroses to make less repetitive code.
> Now it has repetitive code
so you failed

> (Letter T means Type, C - Constructor,
> IM_ARGS(), IM_VALS() - ARGS, VALS for intermediate (protected) constructor)
¿what are you talking about?
¿why didn't you post those macro definitions?


1
2
inline TFrame::TFrame(IM_ARGS(CFRAME_ARGS)) : TBasis(IM_VALS(CBASIS_VALS)) {
    _boundRight = boundRight;
I spend a while wandering why do you want to self-assign, and then realised that your macro expansion probably make `boundRight' a parameter.


1
2
3
4
5
6
7
8
9
10
struct foo{
        TObject* baseObject = 0;
        unsigned orderSize = 30;
        int boundRight = 0;
        int boundBottom = 0;
        int startX = 0;
        int startY = 0
};

TFrame::TFrame(/*whatever goes here*/, const foo &bar)

I posted github, there are definitions...

Here they are:
1
2
3
4
5
6
7
8
9
#define IM_ARGS(ARGS)\
        int dummy,\
        unsigned typeIndex,\
        ARGS

#define IM_VALS(VALS)\
        0,\
        UNIQUE_OBJ_TYPE_INDEX,\
        VALS 


What is that struct about? It has nothing to do with the problem.
Well, my bad that I explained things so shitty....
But.

Imagine, I have 1 protected constructor A::A() that has like 10 parameters. This constructor inherits another, and I also have 1 public constructor that inherits protected.
(I need a constructor to be protected because it manipulates with typeIndex, that user shouldn't be able to do)

So I need about 40 words to write just parameters, whether INITIALIZED or NOT.
So, with macroses, I reduce it to about 30, and they look better organized (for me), or no??
I am not sure...

Returning to the struct you've shown...
I don't need such initialization, if I understood it correctly. I must be able to pass these parameters through constructor, and if parameters are missing, they are set to defaults.
Last edited on
This constructor inherits another

You are being very confusing with pronouns. Is "This" the A constructor? Or some other constructor?
Can you describe another?
Also constructors are not described as inheritors; classes can inherit. This is just me being persnickety about vocabulary.

and I also have 1 public constructor that inherits protected.

Can you name the class that this public constructor belongs too? Are we to assume that the protected one is class A?

So far in my confused mind I see (and I put this together with the knowledge that you have 3 daisy chained):
class Another -> class A -> class ProtectedInheritor ????
I thought class A would be the top class seeing as how it has 10 parameters.

It has nothing to do with the problem.
Well, my bad that I explained things so shitty....

We could identify your problem, if you explain the problem.
I still do not know what you want to accomplish.

As for using a struct instead of a macro for the parameters, there are pros and cons for both. I prefer the macro solution. Both solutions still type check. Both solutions require searching for their definition if you do not know what they mean already. The struct enforces something that I like in python: named parameter passing. The macro provides less typing in the end, and does not require the user to have local struct variables just to pass a set of parameters.

Are you trying to have a unique identifier for every class you initialize that is a descendant of the oldest ancestor? You could just have a static integer be incremented in the oldest ancestor's constructor.
Can you name the class that this public constructor belongs too? Are we to assume that the protected one is class A?

There is a super-class named TObject:
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
class TObject {
    friend class TBasis;
    friend class TComponent;

    private:
        unsigned _typeIndex;

        bool _passFlag;

        TObject* _prevObject;
        TObject* _nextObject;
        TObject* _baseObject;
        TObject* _subObject;

        void loopUpdate();
        void loopDelete();

        virtual void update() = 0;

        unsigned _orderIndex; //little optimization rudiment

    protected:
        TObject(unsigned typeIndex, bool passFlag);

    public:
        unsigned const& typeIndex = _typeIndex;

        bool const& passFlag = _passFlag;

        TObject* const& prevObject = _prevObject;
        TObject* const& nextObject = _nextObject;
        TObject* const& baseObject = _baseObject;
        TObject* const& subObject = _subObject;

        virtual ~TObject();

        virtual void remove() = 0;
};


There are also 2 basic classes inheriting Object: Basis and Component.
Basis:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class TBasis : public TObject {
    friend class TObject;
    friend class TComponent;

    private:
        unsigned _orderSize;

        TComponent* * orderComponent;

        TObject* getPosition(unsigned orderIndex);

        virtual void update() = 0;

    protected:
        TBasis(int dummy, unsigned typeIndex, TObject* baseObject, unsigned orderSize);

    public:
        unsigned const& orderSize = _orderSize;

        virtual ~TBasis();

        void updateAll();
        void remove();
};


Component:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class TComponent : public TObject {
    friend class TObject;
    friend class TBasis;

    private:
        //unsigned _orderIndex;

        virtual void update() = 0;

    protected:
        TComponent(int dummy, unsigned typeIndex, TObject* baseObject/*!= 0*/, unsigned orderIndex);

    public:
        unsigned const& orderIndex = _orderIndex;

        virtual ~TComponent();

        void remove();
};


Object, Basis, Component are all abstract and have only protected constructor.

Let's now take, for example, TSprite::TComponent:
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
class TSprite : public TComponent {
    private:
        spriteset_t* _spriteset;

        int _x;
        int _y;

        unsigned column;
        unsigned row;
        float scale;
        bool mirrorX;
        bool mirrorY;

        virtual void update();

    protected:
        TSprite(IM_ARGS(ARGS));

    public:
        spriteset_t* const& spriteset = _spriteset;

        int const& x = _x;
        int const& y = _y;

        TSprite(DEFS);

        void setSpriteset(spriteset_t* spriteset);
        void setCoords(int x, int y);
};


It has a protected constructor and a public constructor.
So, every class that is not basic (not just Object, Basis or Component) has also public constructor.
Public constructor is for user's purpose to create objects like this:
1
2
3
4
5
6
    Frame = new TFrame();
    new TCursor(Frame);

    World = new TWorld(new TBackground(Frame));
    World->setTilebox(new TTilebox(World))
    new TAllroundScroller(World);


Protected one is to "inherit" (sorry for this, how will it be correct to say?) basic class or another non-basic like this:
1
2
3
inline TSprite::TSprite(IM_ARGS(ARGS)) : TComponent(IM_VALS(CCOMPONENT_VALS)) {
///some code
}

Then public one is empty, as it "inherits" protected (to avoid much repetitive code):
1
2
inline TSprite::TSprite(ARGS) : TSprite(IM_VALS(VALS)) {
}


All this is done to make sure that user does not modify typeIndex by himself.
(Protected has typeIndex, public - doesn't)

As for using a struct instead of a macro for the parameters, there are pros and cons for both. I prefer the macro solution. Both solutions still type check. Both solutions require searching for their definition if you do not know what they mean already. The struct enforces something that I like in python: named parameter passing. The macro provides less typing in the end, and does not require the user to have local struct variables just to pass a set of parameters.
I wasn't even sure if people ever use it for such purpose.
Ty :]

Are you trying to have a unique identifier for every class you initialize that is a descendant of the oldest ancestor? You could just have a static integer be incremented in the oldest ancestor's constructor.
Yep.
I use boost::preprocessor to make unique indexes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# ifndef KENG_MAIN_TYPE_INDEX_HPP_INCLUDED
# define KENG_MAIN_TYPE_INDEX_HPP_INCLUDED
#     include <boost/preprocessor/arithmetic/inc.hpp>
#     include <boost/preprocessor/slot/slot.hpp>
#     define BOOST_PP_VALUE 0
#     include BOOST_PP_ASSIGN_SLOT(1)
#     undef BOOST_PP_VALUE
#     define UNIQUE_OBJ_TYPE_INDEX BOOST_PP_SLOT(1)
#     define OBJ_TYPE_COUNT BOOST_PP_SLOT(1)
# else
#     define BOOST_PP_VALUE BOOST_PP_INC(BOOST_PP_SLOT(1))
#     include BOOST_PP_ASSIGN_SLOT(1)
#     undef BOOST_PP_VALUE
# endif 
If the class is named TClass, then TCLASS_INDEX is its index.
I just need to include this header in every class header.
Last edited on
So every class just needs a unique identifier that needs to be set by the parent? Why pass it as a parameter at all? Just use a static variable.
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
#include <iostream>
#include <mutex>

class A{
public:
    int getID() { return ID; }
protected:
    A() {
    	id_mutex.lock();
    	ID = id++;
    	id_mutex.unlock();
    }
private:
    static std::mutex id_mutex;
    static int id;
    int ID;
};
std::mutex A::id_mutex;
int A::id = 0;

class B : public A {
protected:
    B() {}
};

class C : public B {
public:
    C() {}
};

int main() {
	C take1;
	C take2;
	std::cout << take1.getID() << std::endl;
	std::cout << take2.getID() << std::endl;
	return 0;
}

Edit: Changed my example to have protected constructors, and added a class C with a public constructor.
Last edited on
Nope, every exact object must have a field typeIndex that shows of what class it is. So I know just from the object pointer.
I am making a game.
So for example, I need to show all Mobile Units. I take all Units and check if they are Mobile by typeindex. I could make a bool flag, if the Unit is Mobile, but...
Another example, I need to show all Combat Units. I do same, checking if they are Combat... I could make another one flag, if the Unit is Combat.

If you take much these examples, you will get my idea. TypeIndex is better than 100500 flags, as it takes less memory and the code looks better.
My game will have an editor, and this all functionality will find its use.

This can be done also by making 100500 virtual methods, but this isn't just bad for performance, but also would make code messy.

Edit:
I mean, you can retrieve all Unit's parent classes either by putting some info to every type or make typeIndex bit flag, that contains all types in once. (Just my ideas)
Last edited on
I suggest making an enum. Boost has some pretty cool enum stuff to play with.
You are making this solution much tougher on yourself than it needs to be. This is obvious from how confused several of us have been while trying to help you. Sometimes the simple solution is the winner.
dhayden wrote:
There comes a point where your classes need to trust each other.

Also an enum could be good for saving/loading from files later on in the development phase of your game. If your program creates the identifiers every time it loads, there is not a guarantee that the order of creation will not change eventually. Suddenly all the combat units are now peaceful workers and become demolished when the game loads :(
Topic archived. No new replies allowed.