The C++ "static" and "friend" Keywords

Dr. Lawlor, CS 202, CS, UAF

(See also Gaddis Chapter 14)

So C++ has this keyword "static" that is officially described as a "linkage modifier".  That is, a static variable or function acts differently than an ordinary non-static variable.  Exactly what this means depends on what you apply the keyword to!

Static #1: on a local variable = keeps value across calls

For example, the ordinary "int count" here gets created separately every call, so this always prints "count = 1":
void doStuff(void) {
int count=0; /* not static: get a new count every call */
count++;
cout<<"count = "<<count<<"\n";
}
int foo(void) {
for (int i=0;i<3;i++) doStuff();
return 0;
}

(Try this in NetRun now!)

If you add "static" to a local variable, this makes the local variable retain its value permanently--the value is not destroyed when your function returns.  So this prints "count = 1", then "count = 2", then "count = 3":
void doStuff(void) {
static int count=0; /* static local: retain value across calls */
count++;
cout<<"count = "<<count<<"\n";
}
int foo(void) {
for (int i=0;i<3;i++) doStuff();
return 0;
}

(Try this in NetRun now!)

Static #2: on a global variable or function = invisible from outside

If you put "static" before the declaration of a function or global variable, it can't be seen or called from outside the file. 
static int my_x=17; /* acts like a global, but can't be seen from outside this file */
int foo(void) {
return my_x;
}

(Try this in NetRun now!)

This is handy in bigger programs, where there might be several different functions named "print()", which would normally cause a conflict; but as long as they're declared static ("with static linkage") they stay separate.

Static #3: on a class member = shared between all instances

For members of a class, normally you need an instance of the class to access the member.  For example, we have to declare a "Bar" object before we can access its value:
class Bar {
public:
int value; // ordinary instance variable
};

int foo(void) {
Bar b;
b.value=17;
return b.value;
}

(Try this in NetRun now!)

If you add "static" before a class member, then the member acts like a global variable: it's shared between all instances of the class, and you don't need to create a class instance to access the variable.  To refer to the variable, you say "classname::variablename":
class Bar {
public:
static int value; // "static" makes this like a global, not per-instance
};

int foo(void) {
return Bar::value;
}

int Bar::value = 17; // must declare storage and initialize the value

(Try this in NetRun now!)

You also have to actually declare the storage for a static member variable, because it's not automatically allocated like with ordinary members. 

Static members are useful for declaring constants inside your class.  For example, the fstream open arguments like "ios::out" are probably some sort of static member.

You can add "static" before a member function too; this makes the member function shared between all the class instances, and callable without an instance of the class:
class Bar {
public:
static int doStuff(void) {cout<<"the doStuff method\n"; return 0;}
};

int foo(void) {
return Bar::doStuff();
}

(Try this in NetRun now!)

Static member functions are sometimes used to create class instances (a "factory" method), or to perform book-keeping for the class.

Here's a little table to help you keep track of the many uses of "static":

"static" on a...
does...
which is useful for...
local variable
keep value across function calls
counters and caches inside a function.
global variable
hides the variable from outside files
avoiding conflicts in big programs
function
hides the fun ction from outside files avoiding link conflicts in big programs
member variable
shares variable across instances
class-local constants, counters and caches
member function
shares function across instances
class-related housekeeping

"Friend": When Private is too Private

So C++ has these nice access control keywords "public" and "private".  "private" variables and functions can't be accessed from outside the class.   But sometimes, you really need to get at a class's "private" parts, for example in a closely related class.  You can do this by making the accessing class a "friend" of the examined class. 

For example, this is normally a compile error, because the Clam's pearl variable is private:
class Clam {
private:
int pearl;
public:
Clam() {pearl=7;}
};
class Diver {
public:
int search(Clam &c) {
return c.pearl; // oops! Access error!
}
};

int foo(void) {
Clam c;
Diver d;
return d.search(c);
}

(Try this in NetRun now!)

But you can make this work by making the Clam a "friend" of the Diver.  The "friend" line can go anywhere inside the Clam declaration:
class Clam {
private:
int pearl;
public:
Clam() {pearl=7;}
friend class Diver; // the Diver can access my private pearl
};

(Try this in NetRun now!)

Note that this is a really weird version of friendship: your friend can access all your private variables, like he has a key to your house.   "friend" is not commutative: just because he's got a key to your house, you don't have a key to his house.  Having too many "friend"s is hence pretty dangerous, because any of them can ransack your house, and you won't even know which one did it.

You can also declare a function as your "friend".  This allows us to get rid of the "Diver" entirely:
class Clam {
private:
int pearl;
public:
Clam() {pearl=7;}
friend int foo(void); // the foo function can access my private pearl
};

int foo(void) {
Clam c;
return c.pearl;
}

(Try this in NetRun now!)

You can even define the entire "friend" function inside your class.  This gives a little nicer syntax than a static method (which would be "Clam::shazam"):
class Clam {
private:
int pearl;
public:
Clam() {pearl=7;}
friend int shazam(Clam &c) { // a *separate* function as a friend
return c.pearl;
}
};

int foo(void) {
Clam c;
return shazam(c);
}

(Try this in NetRun now!)

The "shazam" function doesn't even exist outside my class here.  One strange caveat: "friend" functions can only be defined inside a class if they mention the name of the class in their argument list ("argument dependent lookup"), or if they have a predefined function prototype.  If neither of these is true (for example, a "friend int ted(int x) { ... }"), then a friend function defined inside a class is totally inaccessible!

Generally speaking, "friend" should be avoided.