Thread: Static member variables

  1. #1
    Registered User
    Join Date
    Oct 2005
    Posts
    271

    Static member variables

    I have one base class and a derived class with a static member variable in the base:

    Code:
    class A{
    private:
    
    static int i; string myname;
    public:
    A(); void inc(); int getI() const;
    }; class B:public A{ public:
    B();
    };
    Then in a code file, I have:
    Code:
    int A::i=0;
    
    void A::inc(){
    
    i++;
    } int A::getI(){
    return i;
    } A::A(){
    inc(); myname = "A";
    } B::B(){
    inc(); myname = "B";
    }
    And finally, in main I have:
    Code:
      A a1;
      std::cout << "i_val for class a1 is: " << a1.getI() << std::endl;
      A a2;
      std::cout << "i_val for class a2 is: " << a2.getI() << std::endl;
      B b1;
      std::cout << "i_val for class b1 is: " << b1.getI() << std::endl;
      B b2;
      std::cout << "i_val for class b2 is: " << b2.getI() << std::endl;
    The result is:
    Code:
    i_val for class a1 is: 1
    i_val for class a2 is: 2
    i_val for class b1 is: 4
    i_val for class b2 is: 6
    I was expecting the numbers to be in sequential order: 1, 2, 3, 4. Instead, I discovered that when instantiating B, the constructor for A was invoked as well which is why the "i" value is incrementing by 2.

    So my question is, is there a way to make sure that the constructor for B and B only is invoked when I instantiate B?

    If not, does that mean every base constructor is invoked if you instantiate a derived class? And what would be advantage of this?

    I did try declaring the constructor as virtual, but the compiler wasn't buying that (so now I know you cannot declare constructors as virtual).

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> is there a way to make sure that the constructor for B and B only is invoked when I instantiate B?
    No. A constructor must be called for each base class.

    >> does that mean every base constructor is invoked if you instantiate a derived class?
    Depends on what you mean. Only one base class constructor is called per base class when you instantiate a derived class. If you have multiple base classes or base classes that derive from other classes, then each class in the chain will have one and only one constructor called.

    You can specify which base class constructor to use in the initializer list. If you don't specify one, the default constructor is used. This means that if you create a second constructor for A that takes a parameter and doesn't call inc(), then you can call that constructor from B to avoid inc() being called.

    However, a better design in this contrived case would be to not call inc() from the B constructor and let the A constructor do that.

  3. #3
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Thanks, that explains it.

  4. #4
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by cunnus88 View Post
    So my question is, is there a way to make sure that the constructor for B and B only is invoked when I instantiate B?
    Even if possible (it isn't), I don't see why you'd want to do that. If A inherits from B, in other words, A is a B, why would you want the B-part of the object to be uninitialized?

  5. #5
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    Quote Originally Posted by brewbuck View Post
    why would you want the B-part of the object to be uninitialized?
    No, I was wondering why the constructor is called twice and whether there was a way to restrict it so that it is called only once?

    It's just that I'm still fuzzy about why other derived/overridden member functions only invoke the one in the derived class, whereas the constructor is called twice even if I have overridden it. Even the destructor is called only once, I think.

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Nope, the destructor is called for all the base classes, and the derived class just like the constructor.

    The reason constructors and destructors are called up and down the hierarchy, rather than just one version being called like for normal functions, is because each class in the hierarchy is supposed to know how to construct and destruct itself, without necessarily giving that information to derived classes. Good design means that the derived class doesn't know how the base class works, and doesn't know how to properly initialize it. By forcing a constructor for the base class to be called when a derived class is being created, you are allowing the base class to initialize its part of the object in a way it knows how to.

  7. #7
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    You think wrong. Or right, depending on the point of view, but under the point of view where the destructor is called only once, the constructor is called only once, too.

    A class is a black box. It exposes an interface to the world via public: and friends. It may expose a somewhat more elaborate interface to derived classes via protected:. Everything else is internal to the class.

    As it is internal to the class, only the class itself can initialize and clean up the stuff. The purpose of a class's constructors is to do this initializing. The purpose of the destructor is to do the cleaning.

    Therefore, a class's constructor MUST be called on creation of an instance of the class, no matter what. If the constructor isn't called, in the view of C++, you do not have an object. You have a block of memory. The constructor call is what makes it an object.
    Similarly, the destructor MUST be called on destruction of an instance, because otherwise you have an object but no memory.

    The language enforces this by guaranteeing that the constructor is called for absolutely every object created, and if the constructor cannot finish due to an exception, the object is not created, everything is taken apart, memory is freed, and so on. No constructor, no object. End of story.

    When a class has members, these members need to be initialized. The compiler enforces that constructors are called for all members. You can use initializer lists to specify which constructors, but you cannot prevent the call. If a member constructor fails, your own constructor never runs. The compiler also guarantees that the destructors of all fully constructed member objects are called, no matter what.

    In many ways, base classes are like members. The derived class cannot initialize its base sub-object, because the base is a black box even towards its derived class. The base's constructor must take care of that. Therefore, the base's constructor MUST be called, whatever happens. And that's that.

    In the end, each constructor is called only once for the creation of an object. But the object consists of many sub-objects, and the appropriate constructor is called for each of these sub-objects.


    Member functions are different. But then, member functions are different. They're just functions. Constructors and destructors are special.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  8. #8
    Registered User
    Join Date
    Oct 2005
    Posts
    271
    I still don't quite grasp why a derived class can't just call its own constructor (and only its own constructor) and be done with it. So would it still be "correct" if I understood it this way?

    When I ran gdb on my code and looked at an instance of "B", I saw an instance of "A" nested inside it. So obviously, if there's going to an instance of a base class inside the instance of a derived class, a constructor will have to be called on the base class.

    If that's the case, I understand why (in terms of compiler implementation) the constructors of the base class are called as well. However, why that would be necessary from a design-oriented perspective is still beyond me.

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    Because A is an entity all by itself. B is not supposed to know how A works. How can B know how to initialize A if it doesn't know how A works?

    The best reason the base class constructors must be called is a design reason, not a compiler reason. Re-read the above responses but assume that we're talking about design and not compiler-related implementation, since I think that might be where you are confused.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  2. Static functions.... why?
    By patricio2626 in forum C++ Programming
    Replies: 4
    Last Post: 04-02-2007, 08:06 PM
  3. Static member functions more efficient?
    By drrngrvy in forum C++ Programming
    Replies: 6
    Last Post: 06-16-2006, 07:07 AM
  4. Problem with Visual C++ Object-Oriented Programming Book.
    By GameGenie in forum C++ Programming
    Replies: 9
    Last Post: 08-29-2005, 11:21 PM
  5. opengl program as win API menu item
    By SAMSAM in forum Game Programming
    Replies: 1
    Last Post: 03-03-2003, 07:48 PM