Static Class Variables, Inheritance, and Polymorphism

Discussion in 'C++' started by crjjrc, Apr 3, 2007.

  1. crjjrc

    crjjrc Guest

    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
    crjjrc, Apr 3, 2007
    #1
    1. Advertising

  2. crjjrc

    peter koch Guest

    On 3 Apr., 18:45, "crjjrc" <> wrote:
    > 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
    peter koch, Apr 3, 2007
    #2
    1. Advertising

  3. crjjrc

    bjeremy Guest

    crjjrc wrote:
    > 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...
    bjeremy, Apr 3, 2007
    #3
  4. crjjrc

    Fei Liu Guest

    crjjrc wrote:
    > 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
    Fei Liu, Apr 3, 2007
    #4
  5. crjjrc

    verdverm Guest

    On Apr 3, 12:45 pm, "crjjrc" <> wrote:
    > 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* >
    verdverm, Apr 4, 2007
    #5
  6. crjjrc

    crjjrc Guest

    On Apr 3, 1:31 pm, "bjeremy" <> wrote:

    > > 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.

    >
    > 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
    crjjrc, Apr 4, 2007
    #6
  7. crjjrc

    James Kanze Guest

    On Apr 4, 7:50 pm, "crjjrc" <> wrote:
    > On Apr 3, 1:31 pm, "bjeremy" <> wrote:


    > > > I've then got a vector declared to hold instances of Base, but it's
    > > > actually filled with various instances of Derived1 and Derived2.


    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.

    > > > 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.


    > > 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.


    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.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 5, 2007
    #7
  8. crjjrc

    crjjrc Guest

    On Apr 5, 4:53 am, "James Kanze" <> wrote:

    > > > > I've then got a vector declared to hold instances of Base, but it's
    > > > > actually filled with various instances of Derived1 and Derived2.

    >
    > 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.

    > > 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.


    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
    crjjrc, Apr 5, 2007
    #8
  9. crjjrc

    James Kanze Guest

    On Apr 5, 3:37 pm, "crjjrc" <> wrote:
    > On Apr 5, 4:53 am, "James Kanze" <> wrote:


    > > > > > I've then got a vector declared to hold instances of Base, but it's
    > > > > > actually filled with various instances of Derived1 and Derived2.


    > > 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.


    Yes. You should have been precise. Precision is an important
    quality when programming.

    > > > 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.


    > 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.

    > > 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.


    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.

    --
    James Kanze (Gabi Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
    James Kanze, Apr 5, 2007
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. SaravanaKumar
    Replies:
    6
    Views:
    9,388
    Tony Morris
    Oct 19, 2004
  2. sapropel
    Replies:
    1
    Views:
    590
    Victor Bazarov
    May 14, 2004
  3. Krivenok Dmitry
    Replies:
    13
    Views:
    1,424
    Axter
    Jun 1, 2006
  4. alexroat
    Replies:
    10
    Views:
    2,316
    alexroat
    Nov 25, 2008
  5. Hicham Mouline
    Replies:
    5
    Views:
    2,361
    James Kanze
    Dec 19, 2008
Loading...

Share This Page