对象与对象的关系
在一个系统中,一个对象可能给与不同的对象相关,以下是不同的关系。
- 依赖关系(使用一个)
- 关联关系(使用一个)
- 聚合关系(有一个)
- 组合关系(有一个,用…来实现)
- 继承关系(是一个)
- 类模板
1.依赖(Dependency)
程序类之间的"依赖"关系主要体现出的是一种使用关系,对于两个相对独立的对象,当一个对象负责构造另一个对象的实例,或者当一个对象依赖于另一个对象所提供的服务时,这两个对象之间主要体现为依赖关系。
在类型的设计中,依赖关系主要体现在目标类型的对象(实例),作为当前类型方法的局部对象或者方法的参数类型。
2.关联(Association)
对于两个相互独立的对象,当对象A与另一个对象B存在固定的对应关系时,这两个对象之间为关联关系。关联关系是依赖关系的特例。
在类型的设计中,关联关系主要体现在目标类型的指针(弱关联)或引用(强关联),作为当前类型的属性成员。没有整体和部分的关系,只是有关系而已。
3.关联与聚合
在概念上,它们都是对象实例间的一种静态关系,都是在类的抽象层次上的定义,并且最终都可以通过对象的属性来体现。但它们差别是,聚合关系所涉及的两个类型的对象,在现实世界中的含义有明显的has - a(有一个)的语义**,能够区分哪个是整体,哪个是部分**,而关联所涉及的对象之间没有这种语义,即分不出整体和部分的关系。用…来组成。
class Point // 点
{
private:
float _x;
float _y;
public:
Point():_x(0.0),_y(0.0) {}
Point(float x,float y):_x(x),_y(y) {}
Point(const Point &p):_x(p._x),_y(p._y) // 按位拷贝 inline 函数
{}
Point & operator=(const Point &p) // 按位赋值 inline 函数
{
if(this != &p)
{
_x = p._x;
_y = p._y;
}
return *this;
}
~Point() {}
float & pointX() { return _x;}
const float & pointX() const { return _x;}
float & pointY() { return _y;}
const float & pointY() const { return _y;}
};
class Circle
{
private:
Point _center; // 圆心
float _radius; // 半径
};
//此时整体与部分之间是可分离的,它们可以具有各自的生命周期,
//部分可以属于多个整体对象,也可以为多个整体对象共享。
以下代码可以这样写吗?
class Circle
{
private:
Point _center;
float _radius;
};
public:
Ciecle (int r=0,int x=0,int y=0):_radius(r),_center(x,y);
{
_center=(x,y);
cout<<"create Circle ”<<endl;
}
当使用构造函数的类型转换时,单参的构造函数才有类型转换的能力,所以我们需要加上一个point构造函数的缺醒值。
2.构造函数中的初始化使用方案 减少构造函数的调动次数,比构造函数中花括号里赋值的语句要更好。
4.组合
当对象A是对象B的属性时,称对象B包含对象A。意味着"用…来实现,用…来构造"
相比于聚合,组合是一种耦合度更强的关联关系。存在组合关系的类表示"整体-部分"的关联关系,“整体"负责"部分"的生命周期,他们之间是共生共死的;并且“部分"单独存在时没有任何意义。
例如,People与Soul、Body之间是组合关系,当人的生命周期开始时,必须同时有灵魂和肉体;当人的生命周期结束时,灵魂肉体随之消亡;无论是灵魂还是肉体,都不能单独存在,他们必须作为人的组成部分存在。
以下是的exemple是组合和聚合关系中对象六个系统函数在此关系中的使用特点
exemple 1: 类里定义的构造函数中的类类型 成员没有给出初始化,那么不定义其成员,也不在成员的类中给出缺醒值,那么构造函数无法编译通过。
using namespace std;
class point
{
private:
float _x;
float _y;
public:
point(float x=0, float y=0) :_x(0), _y(0)//给出缺醒值0
{
cout << "Create point " << endl;
_x = x;
_y = y;
}
point(const point& p1) :_x(p1._x), _y(p1._y)
{
cout << "Copy point " << endl;
}
void print()
{
cout << this->_x << endl;
cout << this->_y << endl;
}
};
class rectangle
{
private:
point leftop;
point rightbottom;
public:
rectangle(float x1,float y1,float x2,float y2) :leftop(x1,y1)//,rightbottom(x2,y2)
//这里不给出rightbottom的初始化
{
cout << " Create rectangle" << endl;
}
rectangle(point& a, point& b) :leftop(a), rightbottom(b)
{
cout << " Create rectangle" << endl;
}
rectangle() :leftop(0, 0), rightbottom(0, 0)
{
cout << " Create rectangle" << endl;
}
rectangle(const rectangle& s1) :leftop(s1.leftop),rightbottom(s1.rightbottom)
{
cout << " Copy rectangle" << endl;
}
void print()
{
this->leftop.print() ;
this->rightbottom.print();
}
};
exemple 2:类里定义的构造函数中的类类型 成员没有给出初始化,成员定义时,其为类型的强转(只能单参),成员的类里也要给出缺醒值:
using namespace std;
class point
{
private:
float _x;
float _y;
public:
point(float x=0, float y=0) :_x(0), _y(0)//给出缺醒值0
{
cout << "Create point " << endl;
_x = x;
_y = y;
}
point(const point& p1) :_x(p1._x), _y(p1._y)
{
cout << "Copy point " << endl;
}
void print()
{
cout << this->_x << endl;
cout << this->_y << endl;
}
};
class rectangle
{
private:
point leftop;
point rightbottom;
public:
rectangle(float x1,float y1,float x2,float y2) :leftop(x1,y1)//,rightbottom(x2,y2)
{
rightbottom(x2,y2);//类型的强转,必须是单参。这里只有一个值是有效的。
cout << " Create rectangle" << endl;
}
rectangle(point& a, point& b) :leftop(a), rightbottom(b)
{
cout << " Create rectangle" << endl;
}
rectangle() :leftop(0, 0), rightbottom(0, 0)
{
cout << " Create rectangle" << endl;
}
rectangle(const rectangle& s1) :leftop(s1.leftop),rightbottom(s1.rightbottom)
{
cout << " Copy rectangle" << endl;
}
void print()
{
this->leftop.print() ;
this->rightbottom.print();
}
};
int main()
{
rectangle r3(20,2,60,6);
rectangle r1(10,20,30,35);
r1 = r3;
r1.print();
return 0;
}
打印结果分析: 构造函数中的rightbottom(x2,y2),将y2最先传入(从右向左传),因为类型转换是单参,x2没有利用,最后的结果“0”是构造函数给出的缺醒值;
exemple 3:拷贝构造函数中类类型 成员没有给出初始化,则调动的是成员类型的构造函数而不是拷贝构造;
拷贝构造函数可以设置不完全拷贝对象的值而自己定义,但要给出缺醒值。
using namespace std;
class point
{
private:
float _x;
float _y;
public:
point(float x=3, float y=8) :_x(0), _y(0)
{
cout << "Create point " << endl;
_x = x;
_y = y;
}
point(const point& p1) :_x(p1._x), _y(p1._y)
{
cout << "Copy point " << endl;
}
};
class rectangle
{
private:
point leftop;
point rightbottom;
public:
rectangle(float x1,float y1,float x2,float y2) :leftop(x1,y1),rightbottom(x2,y2)
{
cout << " Create rectangle" << endl;
}
rectangle(point& a, point& b) :leftop(a), rightbottom(b)
{
cout << " Create rectangle" << endl;
}
rectangle() :leftop(0, 0), rightbottom(0, 0)
{
cout << " Create rectangle" << endl;
}
rectangle(const rectangle& s1) :leftop(s1.leftop)//,rightbottom(s1.rightbottom)
{
rightbottom=(7, 7);
cout << " Copy rectangle" << endl;
}
};
int main()
{
rectangle r3(20,2,60,6);
rectangle r1(r3);
r1.print();
return 0;
}
打印结果:(7 和 8的结果是我们自己定义的而不是拷贝得来)
exemple 4:赋值函数中类类型 成员没有给出初始化,则可能根据用户的自己定义而赋值一部分,另一部分自己定义;
using namespace std;
class point
{
private:
float _x;
float _y;
public:
point(float x=3, float y=8) :_x(0), _y(0)
{
cout << "Create point " << endl;
_x = x;
_y = y;
}
point(const point& p1) :_x(p1._x), _y(p1._y)
{
cout << "Copy point " << endl;
}
};
class rectangle
{
private:
point leftop;
point rightbottom;
public:
rectangle(float x1,float y1,float x2,float y2) :leftop(x1,y1),rightbottom(x2,y2)
{
cout << " Create rectangle" << endl;
}
rectangle(point& a, point& b) :leftop(a), rightbottom(b)
{
cout << " Create rectangle" << endl;
}
rectangle() :leftop(0, 0), rightbottom(0, 0)
{
cout << " Create rectangle" << endl;
}
rectangle(const rectangle& s1) :leftop(s1.leftop),rightbottom(s1.rightbottom)
{
cout << " Copy rectangle" << endl;
}
~rectangle()
{
cout << " Destroy rectangle" << endl;
}
rectangle& operator=(const rectangle &r1)
{
leftop = r1.leftop;
//rightbottom = r1.rightbottom;
cout << "operator =" << endl;
return *this;
}
};
int main()
{
rectangle r3(20,2,60,6);
rectangle r1(1,1,1,1);
r1 = r3;
r1.print();
return 0;
}
打印结果:(赋值了一部分而已)
5.继承关系