1.Composition复合
has a的关系,表示一个类是另一个类的成员变量,一个类包含另一个类
class A {...};
class B
{
public:
B(){}
~B(){}
private:
A a;
int b;
};
复合关系下的构造和析构
构造由内而外
Container的构造函数首先调用Component的default构造函数,然后才执行自己。
Container::Container(…):Component() {…};析构由内而外
Container的析构函数首先执行自己,然后才调用Component的析构函数。 Container::~Container { … ~Component(); }
具体事例
构造-由内而外:B的构造函数会首先调用A的默认构造函数(编译器自己调用,如果需要传递参数,需要在初始化列表显示调用),然后在调用自己的构
B::B(...):A()
{
...
}析构-由外而内:B的析构函数首先执行自己的,然后才调用A的析构函数
B::~B(...)
{
...
~A();
}
Adapter模式
新需求所要求的所有功能在一个已有的C类中已经全部实现,但是C中功能繁多,此时可以设计一个类D对C的功能进行一次封装,仅暴露需要的结构结构,此时就非常适合Composition关系
class C {...};
class D
{
public:
void func() { c.func(); }
private:
C c;
};
2.Delegation委托. (Composition by Reference)
has a point
类的成员变量是另一个类的指针,
class A{...};
class B
{
public:
B(){}
~B(){}
private:
A *a;
int b;
};
这种方法有个名词 pImpl(Pointer to IMPLementation) or Handle/Body,简单理解就是接口与实现分离
参考链接:
典型用例
C++11中的string就是用了这种方法,方法和实际实现分离,这样就可以在两个字符串相同的时候,就使用同一块内存,当其中一个发生改变时就重新分配一块内存
#include <stdio.h>
#include <string>
using std::string;
int main(int argc, char *argv[])
{
string s1("123456789");
string s2(s1);
string s3("123456789");
printf("s1=%p, s2=%p, s3=%p\n", s1.c_str() , s2.c_str(), s3.c_str()); //c_str() 返回字符串的首字符地址
s1 += "00";
printf("s1=%c, s2=%c, s3=%c\n", &s1 , &s2, &s3);
printf("s1=%p, s2=%p, s3=%p\n", s1.c_str() , s2.c_str(), s3.c_str());
return 0;
}
/*
TDM-GCC 4.49.2 64-bit result:
s1=0000000000B41488, s2=0000000000B41488, s3=0000000000B414B8
s1=0000000000B414E8, s2=0000000000B41488, s3=0000000000B414B8
TDM-GCC 4.49.2 32-bit result:
s1=00C90E34, s2=00C90E34, s3=00C90E54
s1=00C9132C, s2=00C90E34, s3=00C90E54
*/
class A
{
public:
A(){}
virtual ~A(){}
}
class B : public A
{
};
“`
构造与析构
构造-由内而外:B的构造函数首先调用A的默认构造函数,然后在执行自己
B::B(): A()
{
…
};
析构-由外而内:B的析构函数首先执行自己,然后才调用A的析构函数
B::~B(…)
{
…
~A();
};
注意:基类的析构函数必须是virual的,否则会出现undefined behavior
4.应用
观察者模式
组合模式Composite结构型
原型模式prototype