zoukankan      html  css  js  c++  java
  • 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

      这就是所谓的桥接关系

  • 相关阅读:
    Atitit.加密算法ati Aes的框架设计
    Atitit.加密算法ati Aes的框架设计
    Atitit.分布式远程调用  rpc  rmi  CORBA的关系
    Atitit.分布式远程调用  rpc  rmi  CORBA的关系
    Atitit.事件机制 与 消息机制的联系与区别
    Atitit.事件机制 与 消息机制的联系与区别
    Atitit  godaddy 文件权限 root权限设置
    Atitit  godaddy 文件权限 root权限设置
    Atitit.atiRI  与 远程调用的理论and 设计
    Atitit.atiRI  与 远程调用的理论and 设计
  • 原文地址:https://www.cnblogs.com/liusiluandzhangkun/p/9115624.html
Copyright © 2011-2022 走看看