4、C++快速入门2

1、抽象类

  如果一个类里面有纯虚函数,其被编译器认为是一个抽象类,抽象类不能用来实例化一个对象

  纯虚函数定义:virtual void 函数名(void)=  0;

  抽象类是给派生类定义好接口函数,如果派生类不实现抽象类中的所有纯虚函数,这个派生类还是一个抽象类,不能实例化对象

 

2、抽象类界面

  一个程序由多个人编写,分为:

  应用编写:使用类

  类编写:提供类(把提供类编译成库)

  eg:Makefile内容

  Human:main.o libHuman,so

    g++ -o $@ $< -L./ -lHuman

  %.o:%.cpp

    g++ -fPIC -c -o $@ $<

  libHuman.so:Englishman.o Chinese.o Human.o

    g++ -shared  -o $@ $^ 

  make后执行命令:LD_LIBRARY_PATH=./ ./Human

  这个时候如果修改Englishman.cpp ,make libHuman.so的时候只会重新生成libHuman.so,不会重新生成应用程序

 

  对上面那个Makefile,如果.h和.cpp都发送了变化,这个时候如果仅make  libHuman.so,运行的时候程序会崩溃,怎么样解决这种问题?

  解决办法是main.c中仅包含一个头文件a.h,main中需要实例化某个对象的时候让该类提供一个函数,这个函数在a.h中声明,并在类中实现:

  eg:在类中Human & CreateEnglishman(char *name,int age,char *address){ return *(new Englishman(name,age,address))};

    在a.h中Human & CreateEnglishman(char *name,int age,char *address);//注意a.h是中间头问题,被main.c包含,a.h也被类所在的cpp包含

  注意:通过delete 来删除CreateEnglishman返回的对象的时候,是调用huamn的析构函数,所有需要把析构函数声明为虚函数,这样能根据对象的实际情况调用相印的类的析构函数,析构函数不能是纯析构函数,否则在派生类必须要实现同名的析构函数,否则派生类还是抽象类(有纯虚函数的类都是抽象类)

 

3、函数模板

template<typename T>

T& mymax(T& a,T& b)

{

  return (a < b)?b:a;

}

使用的方法:int ia =1,ib =2;mymax(ia,ib);

函数模块只是编译指令,一般写在头文件中,编译程序的时候,编译器根据函数的参数来“推导”模板的参数,然后生成具体的函数

比如上面的使用方法会生成如下代码:

int& mymax(int& a,int& b)

{

  return (a < b)?b:a;

}

函数模版支持两中隐式转换(比如上述mymax函数模版,当传入的a和b的类型不一致时,编译器会报错推导不出函数,仅两张情况例外):

A、const转换,模块参数声明为const:T& mymax(const T&,const T&b);这个时候传入的参数可以不带const属性;

B、数组或函数指针转换:T& mymax(T& a,T& b);如果char a[]="abc";char b="cd";mymax(a,b)会出错,因为a,b在这里实际上是(char[4],char[3]),无法推导出T

 

如果存在多个可匹配的模块函数和普通函数

eg:template<typename T>

const T& mymax(const T& a,const T& b)

{

  return (a<b)?b:a;

}

const T& mymax(T& a,T& b)

{

  return (a<b)?b:a;

}

const int& mymax(const int& a,const int& b)

{

  return (a<b)?b:a;

}

int main(int argc,char **argv)

{

  int ia =1;int ib =2;

  mymax(ia,ib);

}

函数选择过程:

A、列出所有匹配的函数:

  第一个模板函数推导后的函数:mymax(const int& a,const int& b)

  第二个模板函数推导后的函数:mymax(int& a,int& b)

  第三个普通函数:mymax(const int& a,const int& b)

B、根据参数的转换排序:第二个模块和第三个函数排在第一位;第一个模板排在第二位

  第一个模板int->const int

  第二个模板int->int

  第三个函数int->int

C、如果某个候选函数的参数跟调用时传入的参数跟匹配,则选择此候选函数

D、如果这些候选函数的参数匹配度相同

  首先,优先选择普通函数

  其次,对于多个模板函数,选择“更特化”的(更特化指的是参数更特殊、更具体、更细化)

  否则出现二义性错误

 

4、类模块

template<typename T>

class AAA{

private:

  T t;

public:

  void test_func(const T &t);

  void print(void);

}

template<typename T> void AAA<T>::test_func(const T &t)

{

  this->t = t;

  count<<t<<endl;

template<typename T> void AAA<T>::print(void)

{

  cout<<t<<endl;

}

int main(int argc,char **argv)

{

  AAA<int> a;

  a.test_func(1);

  a.print();

 

  AAA<double> b;

  b.test_func(1.23);

  b.print();

  return 0;

}

 

同时如果对当前的类模块不满意,也可以定做上面的类模版

在上面的基础上添加代码:

template<>

class AAA<int>{

public:

  void test_func_int(const int & t)

  {

    cout<<t<<endl;

  }

  void print_int(void);

}

void AAA<int>::print_int(void)

{

  cout<<"for test"<<endl;

}

重写main函数:

int main(int argc,char **argv)

{

  AAA<int> a;

  a.test_func_int(1);

  a.print_int();

 

  AAA<double> b;

  b.test_func(1.23);

  b.print();

  return 0;

}

 

5、异常

三个函数A、B、C,其中A调用B,B调用C

C()

{

  return XX;

}

B()

{

  if(C()){}

  else return -Err;

}

A()

{

  if(B()){}

  else {}

}

如果C出错了,A需要去处理这个错误,就需要一级一级的判断,这样如果存在N级调用的时候会非常麻烦,在C++中通过异常来处理该问题

函数A捕获函数C发出的异常,举例如下:

void C(){

  throw 1;//抛出异常后直接跳到A中的catch处执行了,如果这里抛出的不是int类型的数据,程序会崩溃

}

void B(){

  cout<<"call c...."<<endl;

  C();

  cout<<"After call c...."<<endl;//当在C中抛出异常后,这条语句不会在执行

  }

void A(){

  try{

    B{}

  }catch (int i)

  {

    cout<<"catch exception "<<i<<endl

  }

  //catch (...){}//这里的省略号表示所有异常

}

 当抛出了个派生类的时候,如果catch(基类),会发生隐式转换,catch能捕获异常。

可以在函数后面声明这个函数会抛出那些异常,如果其throw非声明异常,程序会崩溃,不管有没相印的catch:eg :void C() throw(int,double){}

抛出异常如果函数没处理,其实际上是交给系统来处理了,会执行2个函数“unexpected”和“terminate”,unexpected函数用来处理声明之外的异常,terminate函数用来处理catch分支未捕获到的异常,如果都没有会两者都调用

可以通过下面语句修改这个默认的处理函数

eg:set_unexpected(异常处理函数);

也可以设置终止函数:

eg:set_terminate(终止函数名称);

 

6、智能指针(下面的sp就是只能指针)

void test_func(void) {

  Person *p = new Person();

}

int main(int argc,char **argv)

{

  test_func();//没有释放new的Person对象,会造成内存泄漏,知道main函数退出

}

如果test_func改为{Person per;}//局部变量,函数退出时对象就会被释放,调用其析构函数

使用指针也能不会造成内存泄漏的方法:

方法1:

class sp{

private:

  Person *p;

public:

  sp(Person *other)

  {

    p =other;

  }

  ~sp()

  {

    if(p)

      delete p;

  }

}

void test_func(void) {

  sp s = new Person();

}

int main(int argc,char **argv)

{

  test_func();

}

 

对方法一进行修改:

class sp{

private:

  Person *p;

public:

  sp():p(0){}//构造函数p的默认值是0

  sp(Person *other)

  {

    p =other;

  }

  ~sp()

  {

    if(p)

      delete p;

  }

  Person *operator->()//重载->

  {

    return p;

  }

}

void test_func(void) {

  sp s = new Person();

  s->printInfo();//调用的是Person里面的函数,因为“->”重载了

}

int main(int argc,char **argv)

{

  int i;  

  for(i =0;i<2;i++)

    test_func();

}

再次修改:

class sp{

private:

  Person *p;

public:

  sp():p(0){}

  sp(Person *other)

  {

    p =other;

  }

  sp(sp &other)

  {

    p =other.p;

  }

  ~sp()

  {

    if(p)

      delete p;

  }

  Person *operator->()//重载->

  {

    return p;

  }

}

void test_func(sp &other) {

  sp s = other;

  s->printInfo();//调用的是Person里面的函数,因为“->”重载了

}

int main(int argc,char **argv)

{

  int i;  

  sp other = new Person()//编译会出错

/*

  上面这句代码相当与:

  A、Person *p = new Person()

  B、sp tmp(p);相当于调用sp(Person *other)构造函数

  C、两种可能:1、sp other(tmp);相当于调用sp(sp &other)构造函数

          出问题的愿意是sp & other这个引用来指向tmp这个临时变量,这是不对的,引用没法执行一个临时变量;但是const sp &other可以指向tmp,所以修改sp(sp &other)构造函数为sp(const sp &other)

          2、tmp转换成Person*,在调用sp(Person *other)构造函数来生成other

          tmp是一个sp对象,其没办法隐式转换成Person *指针

*/

   test_func(other );  

}

执行结果正确;

但是如果main函数改为下面,程序运行会崩溃:

int main(int argc,char **argv)

{

  int i;  

  sp other = new Person();

  for(i=0;i<2;i++)

   test_func(other );  //原因是第一次退出test_func的时候会释放掉new分配的Person空间,第二次循环的时候在次调用s->printInfo();时候,Person对象已经不存在了,可以通过在Person对象中加一个引用计数,并添加获取、加1、减1三个函数,同时在sp类中所有的构造函数都调用加1函数,析构函数中先调用减1函数,接着调用获取函数来得到引用计数的值,如果为零,就调用delete p来释放,并把p设置为NULL。

}

 

同时还可以在sp中重载“*”

eg:Person& operator*()

  {

    return *p;

  }

在main中

  sp other = new Person();

  (*other).printlnfo();

 

 

可以把sp定义为类模块:

template<typename T>

class sp{

private:

  T *p;

public:

  sp():p(0){}

  sp(T *other)

  {

    p = other;

    p->incStrong();

  }

  sp(const sp &other)

  {

    p = other.p;

    p->incStrong();

  }

  ~sp()

  {

    if(p)

    {

      p->decStrong();

      if(p->getStrongCount() == 0)

      {

        delete p;

        p = NULL;

      }

    }

  }

  T *operator->()

  {

    return p;

  }

  T& operator*()

  {

    return *p;

  }

}

 

template<typename T>

void test_FUNC(SP<T> &other)

{

  sp<T> s =other;

  s->printInfo();

}

 

int main(int argc,char **argv)

{

  sp<Person> other = new Person();

  test_func(other);

}

7、Android轻量级指针(在源码RefBase.h中,sp的相关源码在StrongPointer.h中)

  对上面的代码,引用计数的加1和减1操作不是原子的,在多线程的时候存在风险,在Android源码的RefBase.h中,其也是维护了一个引用计数,其加1和减1如下:

  void incStrong()

  {

    __sync_fech_and_add(&mCount,1);

  }

  void decStrong()

  {

    //__sync_fetch_and_sub(&mCount,1)返回的是减一之前的指

    if(__sync_fetch_and_sub(&mCount,1)==1){

      delete static_case<const T*>(this);

    }

  }

 

  修改6中的代码继承源码中的智能指针:

using namespace std;

using namespace android::RSC;

class Person : public LightRefBase<Person>{//LightRefBase里面有sp的相关代码

public:

  Person(){

    cout<<"Person()"<<endl;

  }

  ~Person()

  {

    cout<<"~Person()"<<endl;

  }

  void printlnfo(void)

  {

    cout<<"just a test function"<<endl;

  }

}

template<typename T>

void test_FUNC(sp<T> &other)

{

  sp<T> s =other;

  s->printInfo();

}

 

int main(int argc,char **argv)

{

  sp<Person> other = new Person();

  test_func(other);

}

 

8、弱指针的引人

  智能指针的缺陷

  eg:test_func()

  {

    sp<Person> a = new Person(); //a指向的对象的count = 1

    sp<Person> b = new Person();//b指向的对象的count = 1

    a->setFather(b);//a引用了b;b所指向的count =2;

    b->setSon(a);//b引用了a;a所指向的count =2;

  }

  test_func程序退出的时候~a和~b执行,两者的count =1,这个时候会产生内存泄漏

  

  eg:

using namespace std;

using namespace android::RSC;

class Person : public LightRefBase<Person>{//LightRefBase里面有sp的相关代码

private:

  sp<Person> father;

  sp<Person> son;

public:

  Person(){

    cout<<"Person()"<<endl;

  }

  ~Person()

  {

    cout<<"~Person()"<<endl;

  }

  void setFather(sp<Person> &father)

  {

    this->father = father;

  }

  void setSon(sp<Person> &son)

  {

    this->son= son;

  }

  void printlnfo(void)

  {

    cout<<"just a test function"<<endl;

  }

}

 

void test_FUNC()

{

    sp<Person> father = new Person(); 

    sp<Person> son = new Person();

    father ->setSon(son );

    son ->setFather(father );

}

 

int main(int argc,char **argv)

{

  test_func(other);

  return 0;

}

执行结果:

Person()

Person()

如果去掉son ->setFather(father );

执行结果:

Person()

Person()

~Person()

~Person()

 

分析原因:如果对象里含有其他对象成员,构造时先构造其他对象成员,在构造对象本事;析构时顺序正好相反

sp<Person> father = new Person(); 

1、对于new Person()

1.1 Person对象里面的father被被构造,执行sp的默认构造函数inline sp():m_ptr(0){},什么都没做

1.2 Person对象里面的son被构造,执行sp的默认构造函数inline sp():m_ptr(0){},什么都没做

1.3 Person对象本身被构造

2、Person对象的指针传给“sp<Person> father”

  导致sp(T*other)被调用

  它增加了这个Person对象的引用计数(现在此值等于1)

 

sp<Person> son= new Person(); 

1、对于new Person()

1.1 Person对象里面的father被被构造,执行sp的默认构造函数inline sp():m_ptr(0){},什么都没做

1.2 Person对象里面的son被构造,执行sp的默认构造函数inline sp():m_ptr(0){},什么都没做

1.3 Person对象本身被构造

2、Person对象的指针传给“sp<Person> son”

  导致sp(T*other)被调用

  它增加了这个Person对象的引用计数(现在此值等于1)

 

1、setSon里面执行的是"="操作,sp的“=”符号被重载了,它会再次增加son对象的引用计数变成2了

father ->setSon(son );

1、setFather里面执行的是"="操作,sp的“=”符号被重载了,它会再次增加father对象的引用计数变成2了

son ->setFather(father );

 

当test_func被执行完后,father和son被析构

1、father析构的时候调用~sp():会调用对象的decStrong函数来减1引用计数,还没为0,不会delete掉对象

1、son析构的时候调用~sp():会调用对象的decStrong函数来减1引用计数,还没为0,不会delete掉对象

  对于father指向的对象,其通过father ->setSon(son )引用了son对象,导致son计数变成2了,其可以决定son指向对象的生死,同理son指向的对象,其通过son->setFather(father)引用了father对象,导致father计数变成2了,其可以决定son指向对象的生死

  如果想杀掉father,需要先杀掉son中的引用值,同理杀掉son,需要先杀掉father中的引用值,这样就死锁了。

  强指针/强引用   A指向B,A决定B的生死

  弱指针/弱引用  A指向B,A不能决定B的生死

  本例子这里是强引用,导致死锁,必须引入弱引用或者弱指针,使得father ->setSon(son )时不增加引用计数就可以解决该问题。

 

9、强弱引用(强弱指针)的引入

 在RefBase基类中有定义了两个引用计数,分别用于强弱引用

 强引用的使用sp<Person>,sp的构造函数肯定是调用incStrong来增加强引用计数,析构函数调用decStrong来减少引用计数

   弱引用的使用wp<Person>,wp的构造函数肯定是调用incWeak来增加强引用计数,析构函数调用decWeak来减少引用计数

 eg:本例子需要复制Android源码中的RefBase.cpp到本工程中,还有一些头文件

 举例person9.cpp

  Makefile:

  person9:person9.o RefBase.o

    g++ -o $@ $^

  %.o : %.cpp

    g++ -c -o $@ $< -I include

  clean:

    rm -f *.o person9

 

  person9.cpp

using namespace std;

using namespace android;

class Person : public RefBase{

private:

  wp<Person> father;

  wp<Person> son;

public:

  Person(){

    cout<<"Person()"<<endl;

  }

  ~Person()

  {

    cout<<"~Person()"<<endl;

  }

  void setFather(sp<Person> &father)

  {

    this->father = father;

  }

  void setSon(sp<Person> &son)

  {

    this->son= son;

  }

  void printlnfo(void)

  {

    cout<<"just a test function"<<endl;

  }

}

 

void test_FUNC()

{

    sp<Person> father = new Person(); 

    sp<Person> son = new Person();

    father ->setSon(son );

    son ->setFather(father );

}

 

int main(int argc,char **argv)

{

  test_func(other);

  return 0;

}

执行结果:

Person()

Person()

~Person()

~Person()

解决了强指针相互引用导致死锁的问题

 

eg:

修改上面的main函数:

int main(int argc,char **argv)

{

  wp<Person> s = new Person();

  s->printlnfo();//编译的时候会出错,因为弱指针里面“->”没有重载,也没有重载“*”,因为wp进简单引用,没有控制对象的生死,所以如果重载"->"或者“*”,在使用的时候可能对象已经释放了,存在风险,所以源码中没有重载

  return 0;

}

所以要改为强指针

int main(int argc,char **argv)

{

  sp<Person> s = new Person();

  if(s != 0)

    s->printlnfo();

  return 0;

}

 

eg:修改person.cpp

using namespace std;

using namespace android;

class Person : public RefBase{

private:

  char *name

  wp<Person> father;

  wp<Person> son;

public:

  Person(){

    cout<<"Person()"<<endl;

  }

  Person(char *name){

    cout<<"Person(char *name)"<<endl;

    this->name = name;

  }

  void setFather(sp<Person> &father)

  {

    this->father = father;

  }

  void setSon(sp<Person> &son)

  {

    this->son= son;

  }

  ~Person()

  {

    cout<<"~Person()"<<endl;

  }

  char *getNmae(void)

  {

    return name;

  }

  void printlnfo(void)

  {

    sp<Person> f = father.promote();//弱指针转换成强指针

    sp<Person> s = son.promote();

    cout<<"I am"<<endl;

    if(f  != 0)

      cout<<"My father is "<<f->getName()<<endl;

    if(s != 0)

      cout<<"My son is "<<s->getName<<endl;

  }

}

 

void test_FUNC()

{

    sp<Person> father = new Person("LiYiShi"); 

    sp<Person> son = new Person("LiErShi");

    father ->setSon(son );

    son ->setFather(father );

    father->printInfo();

    son ->printInfo();

}

 

int main(int argc,char **argv)

{

  test_func();

  return 0;

}

执行结果:

Person(char*name)

Person(char*name)

I am LiYiShi My son is LiErShi

I am LiErShi My fatheris LiYiShi 

~Person()

~Person()

本例子使用弱指针解决了相互引用导致的问题,并且将弱指针转换为强指针可以引用对象中的函数。

 

强引用计数永远小与弱引用计数

 

10、单例模式

最简单的单例模式使用一个全局指针,如果指针为空,就new一个对象,否则直接使用

eg:

class Singleton;

Singleton *gInstance;

class Singleton{

public:

  static Singleton *getInstance()

  {

    if(NULL = gInstance)

      gInstance = new Singleton;

    return gInstance;

  }

  Singleton()

  {

    cout<<"singleton()"<<endl;

  }

  void printInfo(){cout<<"This is singleton"<<endl}

};

int main(int argc,char ** argv)

{

  Singleton *s = Singleton::getInstance();

  s->printInfo();

  Singleton *s = Singleton::getInstance();

  s->printInfo();

  Singleton *s = Singleton::getInstance();

  s->printInfo();

  return 0;

}

执行结果:

Singleton()//只会执行一次构造函数

This is singleton

This is singleton

This is singleton

 

修改main函数:

void *start_routine_thread1(void *arg)

{

  cout<<"this is thread 1...."<<endl

  Singleton *s = Singleton::getInstance();

  s->printInfo();

  return NULL;

}

void *start_routine_thread2(void *arg)

{

  cout<<"this is thread 2...."<<endl

  Singleton *s = Singleton::getInstance();

  s->printInfo();

  return NULL;

}

int main(int argc,char ** argv)

{

  //创建线程,在线程里也去调用Singleton::getInstance()

  pthread_t thread1ID;

  pthread_t thread2ID;

 

  pthread_create(&thread1ID,NULL,start_routine_thread1,NULL);

  pthread_create(&thread2ID,NULL,start_routine_thread2,NULL);

  sleep();

  return 0;

}

上面的例子还是存在风险,如果两个线程同时执行,存在几率调用两次构造函数,改进方法是给那段代码加上锁;

eg:

 static pthread_mutex_t g_tMutex = PTHREAD_MUTEX_INITIALIZE;

 class Singleton{

  static Singleton *getInstance()

  {  

    if(NULL = gInstance)

    {

      pthread_mutex_lock(&g_tMutex );

      if(NULL = gInstance)      

        gInstance = new Singleton;

      pthread_mutex_lock(&g_tMutex );
    }

    return gInstance;

  }

}

 

同时如果有人不使用getInstance()来实例化对象,而是调用Singleton *s = new Singleton();甚至Singleton s5,这些都会调用构造函数

解决办法:把构造函数声明为private来解决

优化:

把全局变量gInstance和锁移到类内部,并声明为static

eg:

 class Singleton{

 private:

    static Singleton *gInstance;

    static pthread_mutex_t g_tMutex ;

 public:

  static Singleton * getInstance()

  {。。。。}

  。。。。

}

static在类外初始化:

Singleton *Singleton ::gInstance;

pthread_mutex_t Singleton ::g_tMutex = PTHREAD_MUTEX_INITIALIZE;

 

上面这种单例设计模式被称为懒汉模式(用到时才生存实例对象),对应的还有饿汉模式

饿汉模式就是在类外初始化的时候直接实例化,这个时候也不需要锁了:

Singleton *Singleton ::gInstance = new Singleton();

 

11、桥接模式(android源码中只要发现了impl,其肯定就是使用桥接模式)

作用:将抽象部分和它的实现部分分离,使他们都可以独立地变化

说通俗点就是在一个类里面放另一个类的指针,这个指针指向令一个对象,使用这个指针来访问对象中的函数

举例:给电脑安装操作系统

eg:using namespace std;

class OS{

public :

  virtual void install() = 0;//纯虚函数

}

class LinuxOS : public OS{

public:

  virtual void Install(){cout<<"Install Linux OS"<<endl;}

}

class WindowsOS : public OS{

public:

  virtual void Install(){cout<<"Install Windows OS"<<endl;}

}

class Computer{

public:

  virtual void printInfo() = 0;

}

class MAC:public Computer{

public:

  virtual void printInfo(){cout<<"This isMac"<<endl;};

}

class MacWithLinux: public LinuxOS,public MAC {

public:

  void InstallOS(){printInfo();Install();}

}

class MacWithWindows: public WindowsOS,public MAC {

public:

  void InstallOS(){printInfo();Install();}

}

 

class Lenovo:public Computer{

public:

  virtual void printInfo(){cout<<"This is Lenovo"<<endl;};

}

class LenovoWithLinux: public LinuxOS,public Lenovo {

public:

  void InstallOS(){printInfo();Install();}

}

class LenovoWithWindows: public WindowsOS,public Lenovo {

public:

  void InstallOS(){printInfo();Install();}

}

int main(int argc,char **argv)

{

  MacWithLinux a;

  a.InstallOS();

  LenovoWithLinux b;

  b.InstallOS();

  return 0;

}

上面的这个例子太复杂了如果computer有M个派生类,OS有N个派生类,那么要维护一个M*N的派生类,对于computer和OS我们能否建立连接,也就是说搭一个桥,在computer里面建个指针指向OS就可以了

改进代码如下:

eg:using namespace std;

class OS{

public :

  virtual void installOS_impl() = 0;//纯虚函数

}

class LinuxOS : public OS{

public:

  virtual void installOS_impl(){cout<<"Install Linux OS"<<endl;}

}

class WindowsOS : public OS{

public:

  virtual void installOS_impl(){cout<<"Install Windows OS"<<endl;}

}

class Computer{

public:

  virtual void printInfo() = 0;

  virtual void InstallOS() = 0;

}

class MAC:public Computer{

public:

  virtual void printInfo(){cout<<"This isMac"<<endl;};

  MAC(OS *impl){this->impl = impl};

  void InstallOS(){printinfo();impl->installOS_impl();};

private:

  OS *impl;

}

 

class Lenovo:public Computer{

public:

  virtual void printInfo(){cout<<"This is Lenovo"<<endl;};

  Lenovo(OS *impl){this->impl = impl};

  void InstallOS(){printinfo();impl->installOS_impl();};

private:

  OS *impl;

}

 

int main(int argc,char **argv)

{

  OS *os1 = new linuxOS();

  OS *os2 = new WindowsOS();

  computer *c1 = new Mac(os1 );

  computer *c2 = new Lenovo(os2 );

  c1->InstallOS();

  c2->InstallOS();

return 0;

}

    Computer           OS                     

    InstallOS(抽象部分)                IntallOS_impl(实现部分)

  Mac              Lenovo      Linux   Windows

  在Mac里面存放指针:OS *impl  使用的时候让其指向new Linux或者new Windows

  这就是所谓的桥接关系

posted on 2018-05-31 11:19  拉风摊主  阅读(129)  评论(0编辑  收藏  举报

导航