零、从内存角度看代码。
类代码只有一套,但是可以实例化不同对象,并且调用同样的代码处理位于自己内存区内的变量。
实例化两个变量data1和data2,data1和data2的成员变量的数据分别被存储在了不同内存块中。
每个成员函数有一个隐藏的形参this,此参数指向实例的内存地址。
比如:类Data_Class的成员函数:add( Data_Clasee& this, [显示形参])。
this指向了存储变量 data1 和data2的内存块,那么this->data 就能访问当前实例内存块中的数据,例如: data1.add() , add中的隐藏参数this指向存储data1的内存块,那么 data1的内存块中的data会被修改。
但是类内的静态成员函数不存在 上述这个隐藏的this参数,也就无法区别访问不同的实例的内存块,只能对类内静态变量进行读写等操作。
类内静态成员变量 存储在 静态存储区, 并且全局只存在一个,无论你初始化了多少个实例,使用不同实例访问此静态变量,访问的是同一块内存。类内静态变量,需要再类外进行声明,以使系统对其分配内存,否则会编译错误。
class Data_Clasee
{
public:
Data_Clasee();
~Data_Clasee();
void add(){
data++;}
int data=0;
static int staticData;
}
int Data_Clasee::staticData; //必须写这一句来分配内存,否则编译不通过。
void main()
{
Data_Clasee data1,data2;
data1.add();
data2.add();
}
下面简答介绍C++的几个特性
一、复合(Composition)
构造由内而外
析构由外而内
class Container
{
public:
Iterator Iter; //复合
]
- 应用: Adaptor 适配器 设计模式,在类B内初始化一个类A的实例,并且应用此类A的接口函数自定义自己的接口函数,以将类A的进行修改以适应新的要求。比如:我们以deque(双端队列)为基础,通过进一步封装,实现队列。
templete<class T>
class queue{
deque<T> c; //顺序容器
public:
bool empty(){
return c.empty();}
void push(T & value){
c.push_back(value);}
void pop() {
c.pop_front();}
}
二、委托
类内 定义 其他类的指针变量,比如 ClassA * A;通过指针变量A调用相关函数,来委托实例A完成相关功能。
#include <mutex>
mutex _mutex;
class Iterator
{
private:
Iterator():self(null){
... };
Iterator * self;
public:
Iterator* GetIntance() //单例+懒汉+线程安全
{
if(self==null)
{
_mutex.lock()
if(self==null)
{
self = new Iterator();}
_mutex.unlock();
}
return self;
}
}
class Container
{
public:
Iterator *Iter; //委托
}
void main()
{
Iterator * iter = Iterator::GetInstance();
Container container1,container2;
container1.Iter=iter;
container2.Iter=iter; //均指向同一个 iter, 其中 可以使用单例模式设计 iter.
}
- Handle/Body (Pointer Implemetation) 桥接 设计模式:
将抽象部分与实现部分分离,使它们都可以独立变换。
主要解决:在有很多中可能会变化的情况下,用继承会造成类爆炸问题,不易扩展。
如何解决:把不同的分类分离出来,使它们独立变化,减少它们之间的耦合。
关键代码:将现实独立出来,抽象类依赖现实类。
//将各种App、各种手机全部独立分开,使其自由组合桥接
class App
{
public:
virtual ~App(){
cout << "~App()" << endl; }
virtual void run() = 0;
};
class GameApp :public App
{
public:
vo