UML类图
类
类(class / struct)封装了数据和行为,是面向对象的重要组成部分,它是具有相同 属性、操作、关系 的对象集合的总称。
以猎人类为例:
class Hunter
{
public:
int m_age = 32; //普通的成员变量,属于对象,只有创建对象才会存在
static int m_times; //静态成员变量,属于类,并不属于对象,在不创建对象的情况下仍然存在。(所有对象共享唯一的静态成员变量)
string getName()
{
return m_name;
}
void setName(string name)
{
m_name = name;
}
void goHunting()
{
aiming();
shoot();
}
static void saySorry() //静态成员函数,属于类,并不属于对象;可以直接通过类名调用
{
//静态成员函数只能使用静态成员变量,非静态成员变量是不能直接使用的(但可以间接使用)
string count = to_string(m_times);
cout << "Say sorry to every animal " + count + " times!" << endl;
}
protected:
string m_name = "Jack";
void aiming()
{
cout << "使用" + m_gunName + "瞄准猎物..." << endl;
}
private:
string m_gunName = "AK-47";
void shoot()
{
cout << "使用" + m_gunName + "射击猎物..." << endl;
}
};
int Hunter::m_times = 3;其类图应为:
解释
- 类名 :如为斜体则代表抽象类
- 可见性:+ 表示 public、# 表示 protected、- 表示 private、__(下划线)表示 static
- 属性的表示方式:【可见性】【属性名称】:【类型】= { 可选 }
- 方法的表示方式:【可见性】【方法名称】(【参数名 : 参数类型,……】):【返回值类型】
抽象类、抽象方法及虚函数
- 对于抽象类应使用斜体或 << 抽象类/接口 >>
- 虚函数 的表示方式跟随类名,使用斜体
- 其中抽象方法应使用如 void=0
注释
使用右上角的 带三角折痕的矩形加虚线 来表示注释
类之间的关系
表示类的关系总共有 6 种,这 6 种又可以分为 3 类:
- 泛化:泛化表达了 is a 的关系模型,当 A 以某种形式是一个 B 的时候,就是这种关系,包含了有 2 种关系:继承、实现。
- 关联:关联表达了 has a 的关系模型,当 A 拥有一个 B 的时候,就是这种关系,包含了有 3 种关系:聚合、组合、关联。
- 依赖:依赖表达了 use a 的关系模型,当 A 使用了一个 B 的时候,就是这种关系,包含了 1 种关系:依赖。
- 关系强弱:泛化>组合>聚合>关联>依赖
继承关系
继承关系包含:普通继承关系 和 抽象继承关系
例如定义了一个父类(Bird)和两个子类(Cuckoo、Eagle)
代码:
class Bird
{
public:
string getName()
{
return m_name;
}
void setName(string name)
{
m_name = name;
}
virtual void fly() {}
virtual void eat() {}
protected:
string m_sex;
string m_name;
};
class Cuckoo : public Bird
{
public:
void fly() override
{
cout << "我拍打翅膀飞行..." << endl;
}
void eat() override
{
cout << "我喜欢吃肉肉的小虫子..." << endl;
}
};
class Eagle : public Bird
{
public:
void fly() override
{
cout << "我展翅翱翔..." << endl;
}
void eat() override
{
cout << "我喜欢吃小动物..." << endl;
}
};
UML 类图:
父类 Bird 中的 fly()和 eat() 是 虚函数,它有两个子类 Cuckoo 和 Eagle,两个子类中重写了父类的虚函数,在使用带空心三角的实现表示继承关系的时候,有空心三角的一端指向父类,另一端连接子类。
关联关系
关联(Assocition)关系是类与类之间最常见的一种关系,它是一种结构化的关系,表示一个对象与另一个对象之间有联系,如汽车和轮胎、师傅和徒弟、班级和学生等。在代码中最常见的表现就是将一个类的对象作为另一个类的成员变量,主要包含单向关联和双向关联关系:
- 单向关联关系:
class Parent
{
};
class Child
{
private:
Parent m_father;
};- 双向关联关系:
class Parent
{
private:
Child* m_son;
};
class Child
{
private:
Parent* m_father;
};- 自关联关系:
class Node
{
private:
void* m_data;
Node* m_prev;
Node* m_next;
};组合关系
组合(Composition)关系也表示的是一种整体和部分的关系,但是在组合关系中整体对象可以控制成员对象的生命周期,一旦整体对象不存在,成员对象也不存在,整体对象和成员对象之间具有同生共死的关系,在 UML 中组合关系用带实心菱形的直线表示。
代码,以 树(Tree)和 树根(Root)、树干(Trunk)、树枝(Branch)、树叶(Leaf) 为例:
class Root
{
};
class Trunk
{
};
class Branch
{
};
class Leaf
{
};
class Tree
{
public:
Tree()
{
m_root = new Root;
m_trunk = new Trunk;
m_branch = new Branch;
m_leaf = new Leaf;
}
~Tree()
{
delete m_root;
delete m_trunk;
delete m_branch;
delete m_leaf;
}
private:
Root* m_root;
Trunk* m_trunk;
Branch* m_branch;
Leaf* m_leaf;
};UML 类图:
代码实现组合关系,通常在整体类的构造方法中直接实例化成员类,因为组合关系的整体和部分是共生关系,整体的实例对象被析构的时候它的子对象也会一并被析构。如果通过外部注入,即使整体不存在了,部分还是存在的,这样的话就变成聚合关系了。
聚合关系
聚合(Aggregation)关系表示 整体与部分的关系。在聚合关系中,成员对象是整体的一部分,但是成员对象可以脱离整体对象独立存在。在 UML 中,聚合关系用 带空心菱形的直线 表示。
代码,以 森林(Forest)与 植物(Plant)、动物(Animal)、水(Water)、阳光(Sunshine) 为例:
class Plant
{
};
class Animal
{
};
class Water
{
};
class Sunshine
{
};
class Forest
{
public:
Forest(Plant p, Animal a, Water w, Sunshine s) :
m_plant(p),m_animal(a),m_water(w),m_sun(s)
{
}
private:
Plant m_plant;
Animal m_animal;
Water m_water;
Sunshine m_sun;
};UML 类图:
代码实现聚合关系,成员对象通常以构造方法、Setter 方法的方式注入到整体对象之中,因为成员对象可以脱离整体对象独立存在。
表示聚合关系的线,有空心菱形的一端指向整体对象,另一端连接局部对象。
依赖关系
依赖(Dependency)关系是一种使用关系,特定事物的改变有可能会影响到使用该事物的其他事物,在需要表示一个事物使用另一个事物时使用依赖关系,大多数情况下依赖关系体现在某个类的方法使用另一个类的对象作为参数。
在 UML 中,依赖关系用带箭头的虚线表示,由依赖的一方指向被依赖的一方。
代码,以树木(Tree)的生长,需要将空气(Air)、水(Water)、土壤(Soil)对象作为参数传递给 Tree 类的 grow()方法为例:
class Water
{
};
class Air
{
};
class Soil
{
};
class Tree
{
public:
void grow(Water w, Air a, Soil s)
{
cout << "借助 w 中的水分, s 中的养分和 a 中的二氧化碳, 我就可以茁壮成长了";
}
};UML 类图:

依赖关系通常通过三种方式来实现:
- 将一个类的对象作为另一个类中方法的参数
- 在一个类的方法中将另一个类的对象作为其对象的局部变量
- 在一个类的方法中调用另一个类的静态方法
关联关系、聚合关系、组合关系之间的区别
从上文可以看出,关联关系、聚合关系和组合关系三者之间比较相似,他们的区别:
例 1:
- 关联和聚合的区别主要在于语义上:关联的两个对象之间一般是平等的,聚合则一般是不平等的。
聚合和组合的区别则在语义和实现上都有差别:
- 组合的两个对象之间生命周期有很大的关联,被组合的对象在组合对象创建的同时或者创建之后创建在组合对象销毁之前销毁,聚合则无需考虑这些事情。
- 一般来说被组合对象不能脱离组合对象独立存在,而且也只能属于一个组合对象,聚合则不一样,被聚合的对象可以属于多个聚合对象。
例 2:
- 朋友之间属于关联关系,因为这种关系是平等的,关联关系只是用于表示两个对象之间的一种简单的联系而已。
- 图书馆看书的时候,人和书属于聚合关系。书是可以独立存在的,而且书不仅可以属于自己,也可以属于别人。
- 人和自己的心脏属于组合关系,因为心脏不能脱离人体而独自存在。
结语
本文主要由个人笔记修改而来,仅用于学习,如有错误,恳请斧正。
参考
本文详细介绍了UML类图的基本概念与绘制方法,重点解析了类的表示方式及其元素(如成员变量、方法的可见性标记),并通过猎人类示例展示具体实现。文章还阐述了类之间的六种关系(泛化、关联、依赖),特别说明继承关系中普通继承与抽象继承的区别,辅以鸟类父子类的代码实例和对应UML图示。最后强调了三类关系的强弱顺序:泛化>组合>聚合>关联>依赖。全文采用代码与图形对照的方式,系统性地讲解了UML类图的核心要素。









