CPSC 427a: Object-Oriented Programming

Michael J. Fischer

Lecture 11
October 7, 2010

Name Visibility Revisited

Surprising example 1 1 class A {  
2 protected:  
3   int x;  
4 };  
5 class B : public A {  
6 public:  
7   int f() { return x; }         //  ok  
8   int g(A* a) { return a->x; }  //  privacy violation  
9 }; Result:

tryme1.cpp: In member function ’int B::g(A*)’:  
tryme1.cpp:3: error: ’int A::x’ is protected  
tryme1.cpp:9: error: within this context

Surprising example 2: contrast the following 1 class A { };  
2 class B : public A {};    // <-- public derivation  
3 int main() { A* ap; B* bp;  
4   ap = bp; } Result: OK.

___________________________________________________________ 1 class A { };  
2 class B : private A {};    // <-- private derivation  
3 int main() { A* ap; B* bp;  
4   ap = bp; }

Result:

tryme2.cpp: In function ’int main()’:  
tryme2.cpp:4: error: ’A’ is an inaccessible base of ’B’

Surprising example 3 1 class A { protected: int x; };  
2 class B : protected A {};  
3 int main() { A* ap; B* bp;  
4   ap = bp; } Result:

tryme3.cpp: In function ’int main()’:  
tryme3.cpp:4: error: ’A’ is an inaccessible base of ’B’

Names, Members, and Contexts Data and function names can be declared in many different contexts in C++: in a class, globally, in function parameter lists, and in code blocks (viz. local variables).

Often the same identifier will be declared multiple times in different contexts.

Two steps to determining the meaning of an occurrence of an identifier:

  1. Determine which declaration it refers to.
  2. Determine its accessibility according to the privacy rules.

Declaration and reference contexts Every reference x to a class data or function member has two contexts associated with it:

Accessibility rules apply to class data and function members depend on both the declaration context and the reference context of a reference x.

Declaration context example

Example:

int x = 3;                // declaration context: global  
class A {  
  int x;                  // declaration context: A  
  void f(int x) {...}     // declaration context: parameter  
  void g() {int x; ... }  // declaration context: block local  
};

Reference context example

class A {  
  int x;  
  int f() {return x;}         // reference context A  
  int g(A* p) {return p->x;}  // reference context A  
};  
int main() {  
  A obj;  
  obj.x;                      // reference context global  
}

All three occurrences of x have declaration context A because all three refer to A::x, the data member declared in class A.

Inside and outside class references

A reference x to a data/function member of class A is

For simple classes:

Examples

References to A::x

class A {  
   int x;  
   int f() { return x; }         // inside  
   int g(A* p) { return p->x; }  // inside  
   int h();  
};  
 
int A::h () { return x; }        // inside  
 
#include <iostream>  
int main() {  
  A aObject;  
  std::cout << aObject.x;        // outside  
};

Inherited names

In a derived class, names from the base class are inherited by the derived class, but their privacy settings are altered as described in the last lecture.

The result is that the same member exists in both classes but with possibly different privacy settings.

Question: Which privacy setting is used to determine visibility?

Answer: The one of the declaration class of the referent.

Inheritance example

class A { protected: int x; };  
class B : private A {  
  int f() { return x; }         // ok, x is inside B  
  int g(A* p) { return p->x; }  // not okay, x is outside A  
};

Let bb be an instance of class B. Then bb contains a field x, inherited from class A. This field has two names A::x and B::x.

The names are distinct and may have different privacy attributes. In this example, A::x is protected and B::x is private.

First reference is okay since the declaration context of x is B.

Second reference is not since the declaration context of x is A.

Both occurrences have reference context B.

Inaccessible base class

A base class pointer can only reference an object of a derived class if doing so would not violate the derived class’s privacy. Recall surprising example 2 (bottom): 1 class A { };  
2 class B : private A {};    // <-- private derivation  
3 int main() { A* ap; B* bp;  
4   ap = bp; }

The idea is that with private derivation, the fact that B is derived from A should be completely invisible from the outside.

With protected derivation, it should be completely invisible except to its descendants.

Interacting Classes and UML

What is a Class: Syntax

PIC

Can include global operators in such a diagram, adding a 4th row.

Class Relationships

Class Relationship Between Two Classes

Scenarios in which class B appears in definition of class A?

Class B appears in Definition of Class A

Class B is related with class A

UML diagram for derivation:

PIC

UML diagram for friend:

PIC

B as Data Members in A

Class B objects as data members in class A, e.g.,

These reflect different class relationships:

The association relationship is weaker. A special type of association is called aggregation: when a B object is a “part” of an A object.

B as Data Members in A

UML diagram for composition:

PIC

UML diagram for aggregation:

PIC

UML diagrams for simple association (left) and one-many association (right):

PIC  PIC

Creation and Deletion

Identifying composition, association and aggregation helps with object creation and deletion:

Example: BarGraph Class Interaction

What is the class diagram of the BarGraph program?

What types of relationships do we identify? Why?

Association Relationship

The association relationship can be diverse. Some developers label text describing the relationship on the edge connecting two associated classes.

Later in the course we will explore and see more examples.