Constants In A Uml Diagram

9.12. static Data And Functions

Object-oriented programs allocate memory for member variables inside objects, binding the variables to those objects. So, in a sense, the variables "belong" to the object (and Java calls them instance variables). Programmers access member variables through the bound object with one of the selection operators, either dot or arrow. However, there are situations where programmers may wish to store information associated with an entire class rather than individual objects, or create symbolic constants with class scope. C++ and Java implement class variables with the static keyword. Both languages preserve encapsulation by accessing class variables with static functions (or methods).

static And UML Diagrams

Non-static class features (attributes or operations) belong to individual instances of the class (i.e., to an object). In a C++ program, these features are bound to the object with the "this" pointer. On the other hand, static features belong to the class. Unless otherwise specified, features in a UML class diagram are non-static. The UML denotes static features by underlining the feature in the class diagram. Programmers translate the underlining to the static keyword when they translate the UML class diagram to C++.

The UML widget class diagram.  widget  -------------------  -count : int [underlined in the UML diagram]  -color : int  -alignment : float  -------------------  +widget()  +draw() : void  +get_count() : int [underlined in the UML diagram]  +get_color() : int  +set_color(a_color : int) : void
Denoting static features in a UML class diagram. The UML denotes static features by underlining them. The static keyword may modify attributes and operations alike, and is independent of other modifiers such as public or private.

The Scope Resolution Operator

Programs can access static variables, functions, and even constants through objects. However, these features "belong" to a class, so they exist even when the program hasn't instantiated any objects from the class. Therefore, we must have some notation to access static features without relying on objects. That notation, preferred over using objects even if the program has them, is based on the scope resolution operator, ::.

The scope resolution operator has two operands. The left-hand operand is the name of a scoping construct (e.g., a class or namespace). The right-hand operand is the name of a class feature (a member variable or function). The operator binds the feature to the named class's scope. The operator's name suggests that the scope resolution operator helps the compiler resolve an identifier's or a name's scope. If a program includes two or more functions with the same name and parameter list, programmers use the scope resolution operator to clarify which function they are calling. We'll use the operator extensively for this purpose when we introduce multi-class programs in the next chapter.

static Variables

We use static variables whenever we need to save data that is related to a class but not bound to a particular object. A simple example is counting how many times a program instantiates a class (i.e., how many objects it creates). We encounter several problems if we make the counter a member variable:

  1. If we define the counter as a member variable, we will at best duplicate the data throughout all the instantiated objects. Furthermore, maintaining the correct count in all the objects will introduce a significant amount of additional logic.
  2. The counter is an accumulator. So, where should we initialize it? If we initialize it in the constructor or some other function, we'll reset the count whenever the program creates a new object. Again, preventing this will entail a significant amount of additional logic.
  3. The count is lost when the program destroys all the counted objects.
We could define the counter outside the class, but this violates strong encapsulation. Good object-oriented design hides everything about a class in the class itself. Class-scope or static variables solve these problems.
Foo.h Foo.cpp
class Foo {     private:                  static                  int count;      public:         Foo();                  static                  int get_count(); };
#include "foo.h"  int                  Foo::count = 0;  foo::foo() { 	count++; }  int foo::get_count() { 	return count; }
(a) (b)
Client Memory Layout
#include <iostream> #include "foo.h" using namespace std;  int main() {     foo f0;     foo f1;     foo f2;      cout << f0.get_count() << endl;     cout <<                  foo::get_count()                  << endl;      return 0; }
A picture of three 'Foo' objects. Memory for the class variable 'count' is allocated outside and independent of the three objects.
(c) (d)
Static variables example. static or class variables allow programmers to save data that applies to all class objects rather than to a particular object.
  1. Programmers create class objects with the static keyword. Programs can't access static variables through a this pointer because they don't belong to a particular object. So, programmers typically include static functions in the class.
  2. Programmers define and initialize static variables outside of classes and member functions. Doing this makes them look like dreaded global variables, but their access is still hidden from other parts of the program by binding the variable name to a class and making it private.
  3. Although we can call a static function through an object, for example f2.get_count(), most object-oriented programmers consider using the class name with the scope resolution operator a better practice. Doing this also works if all the objects have been destroyed.
  4. Memory for static variables is allocated outside of all objects, which means that the variable exists before any objects are instantiated and persists after all objects are destroyed.

Class Constants

We've already seen three ways of creating symbolic or named constants, including using the const keyword. Each technique creates global constants or names that can be visible anywhere in a program. But is that a significant problem? Linguists estimate that there are more than a million words in the English language and likely similar numbers in other languages. So, it seems like we should be able to write a program without running out of identifier names. For example, more than 456,000 four-characters patterns, nearly half the number of words in the language, can be created using English's 26-character alphabet, but most of those patterns are meaningless. And even so, programmers may want to give the same name to similar functions, variables, or constants defined in different contexts. I encountered this name-collision problem as a C programmer using libraries created by diverse vendors.

Class constants are a special case of class variables, so the solution follows an already established pattern. The stack class created previously included a symbolic constant named SIZE, which was created inside the class using two keywords: static and const. const means that the value cannot change, and static expands the "ownership" from a particular object to the whole class.

Class Specification Object Instantiation Memory Layout
class stack {     private: 	char st[SIZE]; 	int sp;      public:                  static const                  int SIZE = 100; 	int size() { return sp; } };
stack	r; stack	s; stack	t;
A picture of three stack object, each repesented by a rectangle. The two fields in each stack, sp and st, are representd by two rectangles inside the stack rectangles. One rectangle, representing the static SIZE size variable, stands by itself, outside of the stack rectangle, suggesting that there is only one SIZE that is shared by all stack objects.
(a) (b) (c)
Static and non-static data.
  1. Non-static fields or variables (e.g., st and sp) "belong" to an instance of the class (i.e., to an object). Conversely, static fields (e.g., SIZE ) "belong" to the class as a whole. Together, static and const form a class constant - a symbolic constant defined in the scope of a particular class. static without const creates a class variable - a variable shared by all instances of a class, but whose stored value can change.
  2. A C++ program allocates memory for non-static variables whenever a new object is instantiated, and that memory remains associated with that object until the object is destroyed.
  3. A C++ program allocates memory for static variables when the program is first loaded into main memory to run, and does not deallocate that memory until the program ends. The memory for non-static fields resides inside an object; the memory for static fields resides outside of all objects and so exits independently of any instance of the class.
Allowed Preferred
if (r.size() < r.SIZE) . . . if (r.size() < stack::SIZE) . . .
(a) (b)
Accessing class constants. Client code may have a valid reason to use a class constant, and the const and static keywords make it easy for the client to access the constant.
  1. C++ allows access to class constants through any instance (i.e., object) of the class (highlighted).
  2. The preferred notation (highlighted) accesses class constants through the class name with the scope resolution operator.
The notation class_name::field_name is only valid when used with static data, making the second statement preferred because it conveys to the reader the additional information that SIZE is a stack class constant.

static Functions

I attended an object-oriented conference in early 1990 when the paradigm was gaining popularity. During a two-hour "discussion" (a polite term for a verbal brawl), participants debated the relative merits of extracting data from an object and passing it to a function or just passing the whole object. In frustration, one participant observed, "Taking the liver out of a gorilla is messy and annoys the hell out of the gorilla!" By the end of the "discussion," the consensus was that encapsulation was a critical part of the object-oriented paradigm and worth preserving: Pass the gorilla and let it use its liver on our behalf.

When programs pass objects to member functions, they can pass them as explicit arguments, (appearing between the parentheses of the argument list) or as an implicit argument (see Objects and member functions). Function are bound to and access the member variables of an object through the this pointer (see this binds objects to member functions). But static functions do not have a this pointer, so they can't be bound to an object. That means that static functions cannot access any non-static feature - they cannot access non-static variables and they cannot call non-static functions.

class alpha { 	public:                  static                  int function(int x) {...} };
alpha::function(25);
(a) (b)
class beta {     public:         string to_string(int value)             { return                  std::                  to_string(value); } };
namespace std { 	string to_string(int value); };
(c) (d)
The scope resolution operator. The C++ language includes scoping structures, classes and namespaces, that can create new scopes. The scope resolution operator binds the name of the scoping structure with the variables or functions named in the structure.
  1. An example of a static function.
  2. static functions are accessed with the name of the class and the scope resolution operator (in red).
  3. The to_string function represents a more complex scoping problem. Class beta defines a to_string member function that calls the C++ string class to_string function (see Figure 3). Programmers use the scope resolution operator to resolve the ambiguous use of the to_string(int) function name.
  4. C++ declares the common or standard C++ library functions in the std namespace, and programs can usually access them without ambiguity just by adding the "using" statement at the beginning of a file.

Source: https://icarus.cs.weber.edu/~dab/cs1410/textbook/9.Classes_And_Objects/static.html

Posted by: clintonclintontycere0302089.blogspot.com

Comments