using const members of derived classes in base class.

veri745

Golden Member
Oct 11, 2007
1,163
4
81
*edit* I'm coding in C++

Let say I have a pure virtual base class (call it Base) and two derived classes ClassA and ClassB.

Is there a way to define a constant such that it will be different between the two derived classes but be usable in the base class?

For example, let say I want a constant MAX_VALUE to be 10 in ClassA and 20 in ClassB, and have a function

Code:
bool Base::compareMax(int value)
{
   return (value <= MAX_VALUE);
}
The only way I can think of doing this is to have a pure virtual function
Code:
virtual int getMaxValue()
that is defined in the derived classes.
 
Last edited:

Cogman

Lifer
Sep 19, 2000
10,286
145
106
Code:
#include <iostream>

using namespace std;

class Base
{
    public:
        Base(int constVal);
        const int VAL;
};

class DA : public Base
{
    public:
        DA();
};

class DB : public Base
{
    public:
       DB();
};

Base::Base(int constVal = 21) : VAL(constVal)
{

}

DA::DA() : Base(23)
{

}

DB::DB() : Base(22)
{

}

int main()
{
    DA a;
    DB b;
    Base c;

    cout << a.VAL << endl;
    cout << b.VAL << endl;
    cout << c.VAL << endl;
    return 0;
}

Enjoy. The trick is to have the base object set the constant value based on a passed in parameter, and to set that parameter to have some sort of default.
 

iCyborg

Golden Member
Aug 8, 2008
1,355
63
91
That will work, but that constant is per object instance in your example - I thought he wanted it as a class (static) member. In that case it's not as easy, he can have 'static const int MAX_VALUE' defined differently for subclasses, but he would have to override compareMax() in subclasses then. The alternative would be to play with RTTI and typeid() stuff and cast base* into derived* in Base::compareMax() to have the right MAX_VALUE used.
 

Cogman

Lifer
Sep 19, 2000
10,286
145
106
That will work, but that constant is per object instance in your example - I thought he wanted it as a class (static) member. In that case it's not as easy, he can have 'static const int MAX_VALUE' defined differently for subclasses, but he would have to override compareMax() in subclasses then. The alternative would be to play with RTTI and typeid() stuff and cast base* into derived* in Base::compareMax() to have the right MAX_VALUE used.

The constant is allocated per-object, that is true, however, with what I've done, it will be constant throughout the classes (I'm comfortable wasting 4 bytes per object, or however many it is, it probably won't break the bank.). There is also a chance with the way that it is written that the compiler will automatically set aside the constant value (its slim, but possible), thus saving the space.

Doing it any other way (IE, multiple comparison functions, or a separate constant function) will waste just as much space as what I've done in the example, if not more.
 

veri745

Golden Member
Oct 11, 2007
1,163
4
81
Thanks for the tip Cogman, it's a good one.

Sadly, I don't have the ability to change the parameters in the constructor, and there are several constants that I need to define differently between different derived classes.

Hi iCyborg,
I looked up RTTI a little bit, and it looks like it could be promising. Do you have a suggestion for a clean way to do that type of thing? From my initial impressions, is seems like it might be just a messy if not more so to use typeid().
 

iCyborg

Golden Member
Aug 8, 2008
1,355
63
91
Forget typeid...

You could do something like
Code:
#include <iostream>

using namespace std;

class Base {
public:
	static const int MAX_VALUE = 5;
	Base() {}
	bool compareMax(int i);
	virtual void pv() = 0;
};

class ClassA : public Base {
public:
	static const int MAX_VALUE = 20;
	ClassA() {}
	void pv() {}
};

class ClassB : public Base {
public:
	static const int MAX_VALUE = 10;
	ClassB() {}
	void pv() {}
};

bool Base::compareMax(int i) {
	ClassA* A = dynamic_cast<ClassA*>(this);
	if (A) {
		return (i < ClassA::MAX_VALUE);
	}
	ClassB* B = dynamic_cast<ClassB*>(this);
	if (B) {
		return (i < ClassB::MAX_VALUE);
	}
	return (i < MAX_VALUE);
}

bool test(Base* obj, int i) {
	return obj->compareMax(i);
}

int main()
{

	ClassA* x = new ClassA();
	ClassB* y = new ClassB();

	if (test(x, 15)) 
		cout << "ClassA ok with 15\n"; else cout << "ClassA not ok with 15\n";
	if (test(y, 15)) 
		cout << "ClassB ok with 15\n"; else cout << "ClassB not ok with 15\n";

	return 0;
}}

ClassA is ok, ClassB isn't. If there are more constants, you can do them in the same if block.
It's not pretty to have those dynamic casts, but not sure what can be done better if Cogman's idea can't be used.
 

veri745

Golden Member
Oct 11, 2007
1,163
4
81
Forget typeid...

You could do something like
...trim...
ClassA is ok, ClassB isn't. If there are more constants, you can do them in the same if block.
It's not pretty to have those dynamic casts, but not sure what can be done better if Cogman's idea can't be used.

Hmmm,

Having a branch for each subclass type kind of defeats the purpose in my opinion.

It seems like there truly isn't a good way of accessing constants from a base class without a get() style accessor.

I think this is what I'm going to go with:
Code:
#include<iostream>

using namespace std;

class Base {
public:
    Base() {}
    bool compareMax(int i);
    virtual int getMaxValue() = 0;
};

class ClassA : public Base {
public:
    static const int MAX_VALUE = 20;
    ClassA() {}
    int getMaxValue() {return MAX_VALUE;}
};

class ClassB : public Base {
public:
    static const int MAX_VALUE = 10;
    ClassB() {}
    int getMaxValue() {return MAX_VALUE;}
};

bool Base::compareMax(int i) {
    return (i < getMaxValue());
}

bool test(Base* obj, int i) {
    return obj->compareMax(i);
}

int main()
{

    ClassA* x = new ClassA();
    ClassB* y = new ClassB();

    if (test(x, 15))
        cout << "ClassA ok with 15\n"; else cout << "ClassA not ok with 15\n";
    if (test(y, 15))
        cout << "ClassB ok with 15\n"; else cout << "ClassB not ok with 15\n";

    return 0;
}

I don't like the idea of accessing constants via get() methods, but it's the cleanest way I can come up with.
 

Markbnj

Elite Member <br>Moderator Emeritus
Moderator
Sep 16, 2005
15,682
14
81
www.markbetz.net
I don't do C++ any more, and can think of a couple of ways to get similar behavior in C# using abstract properties or readonly fields. But it seems to me that you're trying to do an end-run around what the definition of a constant is. You want a declaration of a single constant that can be initialized to different values based on context. The key thing about a constant is that it can only be initialized and can't change, so the compiler always knows the value. If you could do what you want then the compiler could be in a situation where it is working with a reference to a base type with a constant member whose value it can't determine without runtime type identification.
 

iCyborg

Golden Member
Aug 8, 2008
1,355
63
91
Hmmm,

Having a branch for each subclass type kind of defeats the purpose in my opinion.

It seems like there truly isn't a good way of accessing constants from a base class without a get() style accessor.
Well, if you're going to introduce and override functions, then you should have overriden compareMax() in the first place, something I mentioned as an option in my first post. This way your compareMax() can't do much on its own and depends on this virtual helper getMaxValue() defined in derived classes just for this purpose.

Also, it's a good habit to use const for member functions not changing objects, which getters definitely are, i.e.
int getMaxValue() const {...}
 

veri745

Golden Member
Oct 11, 2007
1,163
4
81
Well, if you're going to introduce and override functions, then you should have overriden compareMax() in the first place, something I mentioned as an option in my first post. This way your compareMax() can't do much on its own and depends on this virtual helper getMaxValue() defined in derived classes just for this purpose.

Also, it's a good habit to use const for member functions not changing objects, which getters definitely are, i.e.
int getMaxValue() const {...}

You have to understand that my actual usage scenario involves much more complex functions where the only difference I want between subclasses is the values of these constants. I provided the compareMax() example for the sake of simplicity.

I would also like the solution to be expandable to more than two derived classes.

I do appreciate everyone's input, and your advice has been duly noted.
 

degibson

Golden Member
Mar 21, 2008
1,389
0
0
Is there a way to define a constant such that it will be different between the two derived classes but be usable in the base class?

Code:
class Base {
  Base() {}
  virtual Base() = 0;
  virtual int GetConstant() = 0;
};

class A : public Base {
  int GetConstant() { return 7; }
};

class B : public Base {
  int GetConstant() { return 9; }
};
 
Last edited: