Content
1. Introduction [ ^ ]
In this article I would like to discuss UML Class Diagrams from the
C++ perspective. Especially [ Class
Relationships ] are emphasized. Special attention was paid to
clarify related terms and provide corresponding C++ code fragments.
This article presents only a brief introduction to the UML notation
itself, more detailed description could be easily found on the
Internet.
2. CLASS DEFINITION
The graphical representation of a class consists of the class name
(in the case of the abstract class, the name is in italic), member / static
variables (attributes) and member / static functions
(operations). Access to the elements is indicated: [+] ... public,
[#] ... protected, [-] ... private. Static elements are
underlined, virtual member functions are in italic.
|
class Class
{
public:
int m_PublicMemberVariable;
void PublicMemberFunction();
static void StaticFunction();
protected:
int m_ProtectedMemberVariable;
void ProtectedMemberFunction();
virtual void PureVirtualMemberFunction() = 0;
private:
int m_PrivateMemberVariable;
static int m_StaticVariable;
int m_IntVariable;
void PrivateMemberFunction();
int ClassBoolArgsReturnsInt(const Class &Arg1, bool &Arg2);
};
|
|
2.2 Class Template [ ^ ]
It is also possible to define a class template (parametrized class).
It provides abstraction for types. The class template defines
how a concrete class (template class) is generated by substituting of
template parameters (T - in the corner) by a list of template
arguments (int), it is called binding.
|
template<class T>
class List
{
public:
virtual void Add(const T &Item);
private:
std::vector<T> m_Items;
};
class IntList : public List<int> {};
|
|
3. CLASS RELATIONSHIPS
3.1 Inheritance [ ^ ]
Inheritance is used if a class (Rectangle) derives its
behaviour from the base class (Shape). This technique allows us to
produce more specific classes from general ones. Public inheritance
(generalization) means that every object of a derived class is also an
object of the base class (every Rectangle is a Shape but
not vice versa). So in code, a derived class can stand in place of the base
one. Inheritance represents a very strong form of relationship.
|
class Shape {};
class Rectangle : public Shape {};
class Ellipse : public Shape {};
|
|
3.2 Composition [ ^ ]
Composition is used if a class (Circle) is composed
of some inseparable components (center:Point). The lifetime
of components is dependent upon the whole (center:Point and
Circle are created / destroyed together). The object can not exist
without its components. A component belongs to only one object.
A component can be introduced as a value or it can be created dynamically
(it is destroyed in the destructor then). Note that Circle2 in the
fig. below results in the same code as the Circle-Point.
equivalent result:
|
class Point {};
class Circle
{
private:
Point m_Center;
};
|
|
3.3 Aggregation [ ^ ]
Aggregation is used if a class (Train) contains / is
composed of some optional components (Passenger). The
lifetime of components is independent upon the whole (destroying the
whole does not destroy the components). The object can potentially exist
without its components. A component can belong to more than one
object (consider e.g. a Room composed of Walls, a
Wall can belong to more than one Room).
|
class Passenger
{
private:
class Train *m_pTrain;
};
class Train
{
private:
std::vector<Passenger *> m_Passengers;
};
|
|
3.4 Association [ ^ ]
Association is used if two objects have a strong connection,
but neither one is a part of the other. It is the
ability of one object to call a member function of the other.
The association is typically implemented via pointer or reference member
variable. Note that many relationships, initially modelled as associations
within the design phase, are often refined into inheritance,
composition, aggregation or dependency.
|
class Person {};
class Postcard
{
private:
Person *m_pSender;
};
|
|
3.5 Dependency [ ^ ]
Dependency is used if class A (Document) uses
class B (Printer), but A has no member variable of
B (there is no value, reference or pointer member variable of the
Printer type inside the Document class definition).
Dependency is typically used if there is a member / class
function taking an argument of B (Document::Print)
or a function returning B, or B is used somewhere inside
the implementation of A (one class requires another the be
included). Likewise, Dependency indicates that a change in the
interface of class B might require changes in the implementation of
class A. Dependency is the weakest form of relationship.
|
class Printer {};
class Document
{
public:
void Print(Printer &Out);
};
|
|
[ Comments here... ]
|