Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++
Prev Contents / Index Next

static member functions

You can also create static member functions that, like static data members, work for the class as a whole rather than for a particular object of a class. Instead of making a global function that lives in and “pollutes” the global or local namespace, you bring the function inside the class. When you create a static member function, you are expressing an association with a particular class.

You can call a static member function in the ordinary way, with the dot or the arrow, in association with an object. However, it’s more typical to call a static member function by itself, without any specific object, using the scope-resolution operator, like this:

//: C10:SimpleStaticMemberFunction.cpp 
class X {
public:
  static void f(){};
};

int main() {
  X::f();
} ///:~

When you see static member functions in a class, remember that the designer intended that function to be conceptually associated with the class as a whole.

A static member function cannot access ordinary data members, only static data members. It can call only other static member functions. Normally, the address of the current object (this) is quietly passed in when any member function is called, but a static member has no this, which is the reason it cannot access ordinary members. Thus, you get the tiny increase in speed afforded by a global function because a static member function doesn’t have the extra overhead of passing this. At the same time you get the benefits of having the function inside the class.

For data members, static indicates that only one piece of storage for member data exists for all objects of a class. This parallels the use of static to define objects inside a function to mean that only one copy of a local variable is used for all calls of that function.

Here’s an example showing static data members and static member functions used together:

//: C10:StaticMemberFunctions.cpp
class X {
  int i;
  static int j;
public:
  X(int ii = 0) : i(ii) {
     // Non-static member function can access
     // static member function or data:
    j = i;
  }
  int val() const { return i; }
  static int incr() {
    //! i++; // Error: static member function
    // cannot access non-static member data
    return ++j;
  }
  static int f() {
    //! val(); // Error: static member function
    // cannot access non-static member function
    return incr(); // OK -- calls static
  }
};

int X::j = 0;

int main() {
  X x;
  X* xp = &x;
  x.f();
  xp->f();
  X::f(); // Only works with static members
} ///:~

Because they have no this pointer, static member functions can neither access non-static data members nor call non-static member functions.

Notice in main( ) that a static member can be selected using the usual dot or arrow syntax, associating that function with an object, but also with no object (because a static member is associated with a class, not a particular object), using the class name and scope resolution operator.

Here’s an interesting feature: Because of the way initialization happens for static member objects, you can put a static data member of the same class inside that class. Here’s an example that allows only a single object of type Egg to exist by making the constructor private. You can access that object, but you can’t create any new Egg objects:

//: C10:Singleton.cpp
// Static member of same type, ensures that
// only one object of this type exists.
// Also referred to as the "singleton" pattern.
#include <iostream>
using namespace std;

class Egg {
  static Egg e;
  int i;
  Egg(int ii) : i(ii) {}
  Egg(const Egg&); // Prevent copy-construction
public:
  static Egg* instance() { return &e; }
  int val() const { return i; }
};

Egg Egg::e(47);

int main() {
//!  Egg x(1); // Error -- can't create an Egg
  // You can access the single instance:
  cout << Egg::instance()->val() << endl;
} ///:~

The initialization for E happens after the class declaration is complete, so the compiler has all the information it needs to allocate storage and make the constructor call.

To completely prevent the creation of any other objects, something else has been added: a second private constructor called the copy-constructor. At this point in the book, you cannot know why this is necessary since the copy constructor will not be introduced until the next chapter. However, as a sneak preview, if you were to remove the copy-constructor defined in the example above, you’d be able to create an Egg object like this:

Egg e = *Egg::instance();
Egg e2(*Egg::instance());

Both of these use the copy-constructor, so to seal off that possibility the copy-constructor is declared as private (no definition is necessary because it never gets called). A large portion of the next chapter is a discussion of the copy-constructor so it should become clear to you then.

Thinking in C++
Prev Contents / Index Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire