C++进阶--多继承

//###########################################################################
/*
 * 多继承
 *
 *  -- 一个类直接派生自不止一个基类
 *
 *  -- 利弊?
 */


//###########################################################################
/*
 * 多继承
 */


class InputFile {
   public:
   void read();
   private:
   void open();
};

class OutputFile {
   public:
   void write();
   void open();
};

class IOFile : public InputFile, public OutputFile {
};

int main() {
   IOFile f;
}


// Notes:
//   void open();
//   f.open();    //这里编译不过,即使其中一个是私有函数。因为函数匹配性检查在权限检查之前
//正确的调用方式:
//f.Output::open();
//两者类都存在open函数,改进成如下方式


class File {                //         File
   public:                  //         /  \        -
   string name;        // InputFile  OutputFile
   void open();           //         \  /
};                            //        IOFile

class InputFile : virtual public File {
};                              
                                
class OutputFile : virtual public File {
};                              

class IOFile : public InputFile, public OutputFile {
};  // 菱形继承

int main() {
   IOFile f;
   f.open();    //但是这样仍然编译不过,open()二义性
   //f.InputFile::name = "File1";  //不仅open有两个,name也有两个
   //f.OutputFile::name = "File2";
}


//解决方式: 虚继承
//但是引入了一个新问题,基类的初始化用哪个?
//C++提供了在最终派生指定的一个解决办法
class File {     
   public:      
   File(string fname);
};             

class InputFile : virtual public File {
   InputFile(string fname) : File(fname) {}     //这边的File(fname)会被忽略
};                              
                                
class OutputFile : virtual public File {
   OutputFile(string fname) : File(fname) {}    //这边的File(fname)会被忽略
};                              

class IOFile : public InputFile, public OutputFile {
   IOFile(string fname) : OutputFile(fname), InputFile(fname), File(fname) {} //不管派生类有多远,都要负责初始化虚基类
};  

int main() {
   IOFile f;
}


// 既然有这些问题,为什么要用多继承?
/*
 * 接口隔离原则
 * 
 * 将大的接口分割成更小且更专用的接口。从而使用户只需要知道他们感兴趣的方法
 */

//例如,Andy可能总共有500个API,但是如果你只关心他作为工程师的特性,你只需要知道工程师的40个API
class Engineer {
   public:
   ...; // 40 APIs
};

class Son {
   public:
   ...; // 50 APIs
};

...

class Andy : public Engineer, Son {
   public:
   ...; // 500 APIs
   };


/*
 * ISP的好处:
 * 1. 接口易于使用
 * 2. 静态类型安全
 */
/*

// 那么怎么样在享受多继承的好处的同时,避免前面提到的问题
 *  【纯虚类】
 *
 *  虚类: 有一个或多个纯虚函数的类
 *
 *  纯虚类: 
 *  一个类只包含纯虚函数
 *    - 没有数据
 *    - 没有实体函数
 *    - 没有私有和保护的函数
 */

class OutputFile {
   public:
   void write() = 0; //没有初始化及二义性的问题
   void open() = 0;
};



/*
 * 总结:
 * 1. 多继承是一个重要的技术, 即 接口隔离原则
 * 2. 在使用多继承时只从纯虚类派生
 */

猜你喜欢

转载自www.cnblogs.com/logchen/p/10176786.html