Static Class Variables, Inheritance, and Polymorphism

C

crjjrc

Hi, I've got a base class and some derived classes that look something
like this:

class Base {
public:
int getType() { return type; }
private:
static const int type = 0;
};

class Derived1 : public Base {
private:
static const int type = 1;
};

class Derived2 : public Base {
private:
static const int type = 2;
};

I've then got a vector declared to hold instances of Base, but it's
actually filled with various instances of Derived1 and Derived2. On
iterating through and examining each item, I'd like to be able to call
getType() and have the correct derived class's class variable
retrieved. However, I only get 0 returned. I've tried making
getType() virtual in the Base class, but that didn't help anything.

I can get this to work by defining getType() in each class to return a
literal 0, 1, or 2, but I'd think that what I'm trying do should
work. Any ideas? I don't want to dynamically cast if I can avoid it.

Thanks for any help! Let me know if I can frame the problem
differently or provide more info.

- Chris
 
P

peter koch

Hi, I've got a base class and some derived classes that look something
like this:

class Base {
public:
int getType() { return type; }
private:
static const int type = 0;
};

class Derived1 : public Base {
private:
static const int type = 1;
};

class Derived2 : public Base {
private:
static const int type = 2;
};

I've then got a vector declared to hold instances of Base, but it's
actually filled with various instances of Derived1 and Derived2. On
iterating through and examining each item, I'd like to be able to call
getType() and have the correct derived class's class variable
retrieved. However, I only get 0 returned. I've tried making
getType() virtual in the Base class, but that didn't help anything.

I can get this to work by defining getType() in each class to return a
literal 0, 1, or 2, but I'd think that what I'm trying do should
work. Any ideas? I don't want to dynamically cast if I can avoid it.

Thanks for any help! Let me know if I can frame the problem
differently or provide more info.

- Chris

std::vector can not hold polymorphic types (and neither can any other
container). The trick is to use a vector of pointers, either directly
or (IMHO better) using some smart pointer type or using some external
library (I believe boost has special libraries implementing
pointercontainers).

/Peter
 
B

bjeremy

crjjrc said:
Hi, I've got a base class and some derived classes that look something
like this:

class Base {
public:
int getType() { return type; }
private:
static const int type = 0;
};

class Derived1 : public Base {
private:
static const int type = 1;
};

class Derived2 : public Base {
private:
static const int type = 2;
};

I've then got a vector declared to hold instances of Base, but it's
actually filled with various instances of Derived1 and Derived2. On
iterating through and examining each item, I'd like to be able to call
getType() and have the correct derived class's class variable
retrieved. However, I only get 0 returned. I've tried making
getType() virtual in the Base class, but that didn't help anything.

I can get this to work by defining getType() in each class to return a
literal 0, 1, or 2, but I'd think that what I'm trying do should
work. Any ideas? I don't want to dynamically cast if I can avoid it.

Thanks for any help! Let me know if I can frame the problem
differently or provide more info.

- Chris

class Base {
public:
virtual int getType() { return type; }
private:
static const int type = 0;
};

class Derived1 : public Base {
private:
static const int type = 1;
public:
int getType() { return type; }
};

class Derived2 : public Base {
private:
static const int type = 2;
public:
int getType() { return type; }
};

int main(void) {
std::vector<Base*> v;

v.push_back(new Derived1);
v.push_back(new Derived2);
v.push_back(new Derived2);
v.push_back(new Derived1);
v.push_back(new Base);

for (std::vector<Base*>::iterator i = v.begin(); i != v.end(); ++i){
std::cout << (*i)->getType() << std::endl;
}

return 0;
}

I guess I'm assuming you actually want Base to be a non-abstract
class... you may want to have base look more like

class Base {
public:
virtual int getType()=0;
};
and remember now you are not allowed to instantiate Base directly...
 
F

Fei Liu

crjjrc said:
Hi, I've got a base class and some derived classes that look something
like this:

class Base {
public:
int getType() { return type; }
private:
static const int type = 0;
};

class Derived1 : public Base {
private:
static const int type = 1;
};

class Derived2 : public Base {
private:
static const int type = 2;
};

I've then got a vector declared to hold instances of Base, but it's
actually filled with various instances of Derived1 and Derived2. On
iterating through and examining each item, I'd like to be able to call
getType() and have the correct derived class's class variable
retrieved. However, I only get 0 returned. I've tried making
getType() virtual in the Base class, but that didn't help anything.

I can get this to work by defining getType() in each class to return a
literal 0, 1, or 2, but I'd think that what I'm trying do should
work. Any ideas? I don't want to dynamically cast if I can avoid it.

Thanks for any help! Let me know if I can frame the problem
differently or provide more info.

- Chris
Since you didn't post a complete code, I am guess it's most likely due
to the way you declare your vector container, as it's been explained by
other people. It's a good idea to post a compilable code that
demonstrate your problem.

Fei
 
V

verdverm

Hi, I've got a base class and some derived classes that look something
like this:

class Base {
public:
int getType() { return type; }
private:
static const int type = 0;
};

class Derived1 : public Base {
private:
static const int type = 1;
};

class Derived2 : public Base {
private:
static const int type = 2;
};

I've then got a vector declared to hold instances of Base, but it's
actually filled with various instances of Derived1 and Derived2. On
iterating through and examining each item, I'd like to be able to call
getType() and have the correct derived class's class variable
retrieved. However, I only get 0 returned. I've tried making
getType() virtual in the Base class, but that didn't help anything.

I can get this to work by defining getType() in each class to return a
literal 0, 1, or 2, but I'd think that what I'm trying do should
work. Any ideas? I don't want to dynamically cast if I can avoid it.

Thanks for any help! Let me know if I can frame the problem
differently or provide more info.

- Chris


i would ....

class base {
public:
int getType() const { return 0; }
}

class drv1 {
public:
int getType() const { return 1; }
}
..
.. same for others
..

then

vector< Base* >
 
C

crjjrc

class Base {
public:
virtual int getType() { return type; }
private:
static const int type = 0;
};

class Derived1 : public Base {
private:
static const int type = 1;
public:
int getType() { return type; }
};

class Derived2 : public Base {
private:
static const int type = 2;
public:
int getType() { return type; }
};

This is almost identical to what I had, but I didn't define getType
for each derivation, and I only got 0 returned from getType(). I
don't see why getType needs to be defined for each derived class. It
seems like the parent's getType should pull the variable type from the
child for instances of Derived1 and Derived2. type should be a
"virtual" member, I would think. Is this not the case?

- Chris
 
J

James Kanze

No it's not. A vector always holds instances of the type it was
declared with. If you declare std::vector<Base>, it will hold
instances of Base, and nothing else. This is one of the most
important invariants of std::vector.
This is almost identical to what I had, but I didn't define getType
for each derivation, and I only got 0 returned from getType(). I
don't see why getType needs to be defined for each derived class.

Because it's supposed to do something different in each class.
In Base, it returns Base::type, and in Derived1, it returns
Derived1::type. For what you seem to expect, type would have to
be virtual, which isn't possible for two reasons: data types
can't be virtual, and static members can't be virtual.
It
seems like the parent's getType should pull the variable type from the
child for instances of Derived1 and Derived2. type should be a
"virtual" member, I would think.

Why? You haven't declared it virtual. For various reasons, in
fact, data members can't be virtual; only functions. And of
course, static members can't be virtual. Perhaps the reason
data members can't be virtual is because it only makes sense for
static data members; the reason static members can't be virtual
is that virtuality is based on the actual (dynamic) type of the
object, and static members don't have an associated object, so
it doesn't make sense either.

One possible solution here (other than providing the function in
all of the subclasses, which is still probably the best idea) is
to create a non-static member type in the base class, and have
the derived classes pass its value as an argument to the
constructor of Base.
 
C

crjjrc

No it's not. A vector always holds instances of the type it was
declared with. If you declare std::vector<Base>, it will hold
instances of Base, and nothing else. This is one of the most
important invariants of std::vector.

I should have clarified -- I declared a vector to hold pointers to
instances of Base.
Why? You haven't declared it virtual.

In my first post, I said I tried declaring getType() as virtual.
For various reasons, in
fact, data members can't be virtual; only functions. And of
course, static members can't be virtual. Perhaps the reason
data members can't be virtual is because it only makes sense for
static data members; the reason static members can't be virtual
is that virtuality is based on the actual (dynamic) type of the
object, and static members don't have an associated object, so
it doesn't make sense either.

I believe this last comment contains an inconsistency. You say that
virtuality is based on class, but since static members don't have an
associated instance, virtuality doesn't make sense. Well, static
members do have an associated class. If I've got an object of a
derived class, I'd argue that I should be able to access the type
member of the respective class without having to replicate the exact
same function in all derived classes. If I called a virtual function
in the parent's getType(), would I not access the definition of the
function in the derived class? And this function is associated not
with a particular object, but with the object's class. A consistent
language should use overridden members just as they use overridden
functions. Why should data and code be treated differently? This is
a serious question. I'm not trying to argue, and I'd like to really
know why this is the case.

Nevertheless, C++ isn't designed this way. I don't see a compelling
reason why it is not. My solution mentioned in my first post just
avoids members altogether, with functions that return a literal in
each derived class. That makes the most sense for what I need to do.

- Chris
 
J

James Kanze

I should have clarified -- I declared a vector to hold pointers to
instances of Base.

Yes. You should have been precise. Precision is an important
quality when programming.
In my first post, I said I tried declaring getType() as virtual.

And if you override getType() in the derived classes, the
overriding version gets called, no.
I believe this last comment contains an inconsistency. You say that
virtuality is based on class, but since static members don't have an
associated instance, virtuality doesn't make sense.

Virtual resolution is based on the dynamic type of the actual
*object*, not on the static type (the class) that the compiler
sees.
Well, static members do have an associated class.

But they don't have an associated object. So what do you base
the dynamic type on?
If I've got an object of a
derived class, I'd argue that I should be able to access the type
member of the respective class without having to replicate the exact
same function in all derived classes.

In sum, you're arguing for virtual data members. The language
doesn't support them, for various reasons. If you think it
should, write up a proposal, with a detailed and precise
explination of 1) what the benefits of this are, and 2) how it
can be implemented, and the committee will doubtlessly consider
it. (Actually, implementation is fairly trivial, but for the
moment, I fail to see any real benefits, and I can see a lot of
dangers in it.)
If I called a virtual function
in the parent's getType(), would I not access the definition of the
function in the derived class?

Yes. If you declare the function virtual in the base class.
And this function is associated not
with a particular object, but with the object's class.

When you call a non-static member function, you associate it
with an object.
A consistent
language should use overridden members just as they use overridden
functions.

C++ does. You didn't declare the data element virtual, so it is
not treated as virtual.
Why should data and code be treated differently?

It isn't, in C++. Except, of course, that you cannot declare
data virtual.
This is
a serious question. I'm not trying to argue, and I'd like to really
know why this is the case.
Nevertheless, C++ isn't designed this way. I don't see a compelling
reason why it is not. My solution mentioned in my first post just
avoids members altogether, with functions that return a literal in
each derived class. That makes the most sense for what I need to do.

That's the usual solution. The general philosophy in an OO-type
class is that data is an implementation detail of the class
itself; all that counts is functions. One can argue whether
this is right or not, but there is certainly historical
precedent: I don't know of any language which supports
polymorphism on data types.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top