第十五讲 三大面向对象关系(复合、委托、继承)—————面向对象高级开发

1 三大面向对象关系(复合、委托、继承)

1.1 composition(复合)

关系:has-a
在这里插入图片描述

  • 1,构造关系:由内到外
  • 2,析构关系:由外到内
    例如:
#include <iostream>

class Son{
public:
    Son(){std::cout<<"Son construction"<<std::endl;}
    ~Son(){std::cout<<"Son destroy"<<std::endl;}
};

class Mother{
public:
    Mother(){std::cout<<"Mother construction"<<std::endl;}
    ~Mother(){std::cout<<"Mother destroy"<<std::endl;}
private:
    Son son;
};

int main(){
    Mother mother;
    return 0;
}

输出:

Son construction
Mother construction
Mother destroy
Son destroy

1.2 Delegation(委托)【composition by reference】

一种通过引用的特殊的复合
在这里插入图片描述
Pimpl(pointer to implementation):母类只是对外的接口,真正的实现都在子类里,当母类需要动作的时候,就去调用子类。

作用:母类有一个指针去指向实现所有功能的子类,这种手法的好处在于,这个指针还可以去指向不同的实现类,去实现不同的功能,子类不管怎么变动都不影响s母类也就不影响客户端,母类也永远不用再编译。

示例:

#include <iostream>

class Mother;
class Son{//真正的实现
    friend class Mother;
public:
    Son(int data = 0):m_data(data){std::cout<<"Son construction"<<std::endl;}
    ~Son(){std::cout<<"Son destroy"<<std::endl;}
private:
    int m_data;
    void setData(int data){m_data = data;}
    void  printData()const {std::cout<<"data:"<<m_data<<std::endl;}
};

class Mother{//对外接口
public:
    Mother(){std::cout<<"Mother construction"<<std::endl;}
    ~Mother(){std::cout<<"Mother destroy"<<std::endl;}
    void printData(){son->printData();}
    void setData(int data){son->setData(data);}
private:
    Son* son;//Pimpl(pointer to implementation)
};

int main(){
    Mother mother;
    mother.setData(2);
    mother.printData();
    return 0;
}

输出:

Mother construction
data:2
Mother destroy

1.3 Inheritance(继承)

表示:is-a
在这里插入图片描述
调用函数时,是在运行时决定,而不是在编译期间决定。

公有继承:所有公有成员和保护成员保持原装
私有继承:所有公有成员和保护成员都成为派生类的私有成员
保护继承:所有公有成员和保护成员都成为派生类的保护成员

1.3.1 成员函数类型

  • 1,non-virtual函数:不希望被derived(派生类)override(重新定义); 【void fun();】
  • 2,virtual函数:希望被derived类重新定义,且已有默认值;【virtual void fun();】
  • 3,pure函数:一定要重新定义【virtual void fun() = 0;】

1.3.2 使用条件以及示例

条件:

  • 1,函数时虚函数,声明时用virtual修饰;
  • 2,使用指针或引用调用;
  • 3,指针或引用的对象必须是基类。

纯函数: 函数变量列表后加 = 0
声明了纯虚函数的类,不能实例化为对象。必须要实现后,才能实例化。

构造顺序:基类---->派生类
析构顺序:派生类—>基类

范例:

#include <iostream>

class Base{
protected:
    //纯虚函数:无法实例化
    virtual void printData()const = 0;
};

class Father:public Base{//对外接口
public:
    Father(int data = 0):m_data(data){std::cout<<"Father construction"<<std::endl;}
    virtual ~Father(){std::cout<<"Father destroy"<<std::endl;}
    virtual  void print(){std::cout<<"Father print()"<<std::endl;}
protected://仅继承可以访问
    virtual void  printData()const{std::cout<<"Father:"<<m_data<<std::endl;};//纯虚函数

private:
    int m_data;
};

class Son: public  Father{//真正的实现
public:
    Son(int data = 0):m_data(data){std::cout<<"Son construction"<<std::endl;}
    ~Son(){std::cout<<"Son destroy"<<std::endl;}
    void setData(){printData();}
    void print(){std::cout<<"Son print()"<<std::endl;}
private:
    int m_data;
};

int main(){
    Father father;
    Son son;
    father.print();
    son.print();
    //动态绑定
    std::cout<<"动态绑定------------->"<<std::endl;
    Father* fatherP = &father;
    Father& sonP = son;
    fatherP->print();
    sonP.print();
    //显示调用
    std::cout<<"显示调用------------->"<<std::endl;
    sonP.Father::print();

    return 0;
}

输出:

Father construction
Father construction
Son construction
Father print()
Son print()
动态绑定------------->
Father print()
Son print()
显示调用------------->
Father print()
Son destroy
Father destroy
Father destroy

1.3.3 template Mothod设计模式【模板方法模式】

作用:在父类中定义处理流程的框架,在子类中实现具体处理。
MFC中经常用到此方法。

#include <iostream>
using std::cout;

class Base{
private:
    virtual void calculate() = 0;
public:
    void getResult(){
        std::cout<<"satrt:"<<std::endl;
        calculate();//具体实现放在子类
        std::cout<<"end";
    }
};

class Derived: public  Base{
public:
    virtual void calculate(){
        std::cout<<"calculate"<<std::endl;
    }
};

int main( ){
   Derived derive;
   derive.getResult();
    return 0;
}

输出:

satrt:
calculate
end

1.4 继承+复合

在这里插入图片描述

构造顺序:A—>C—>B
析构顺序:B—>C—>A

//计算复合、继承的构造函数先后
#include <iostream>
using std::cout;
using std::endl;

class A{
public:
    A(){cout<<"构造A "<<endl;}
    ~A(){cout<<"析构A "<<endl;}
};

class C{
public:
    C(){cout<<"构造C "<<endl;}
    ~C(){cout<<"析构C "<<endl;}
};

class  B :public A{
public:
    B(){cout<<"构造B "<<endl;}
    ~B(){cout<<"析构B "<<endl;}
private:
    C c;
};



int main( ){
    B b;
    return 0;
}

输出:

构造A 
构造C 
构造B 
析构B 
析构C 
析构A 

1.5 继承 + 委托

1.5.1 案列

解决的问题:一个文件,四个窗口,当文件变化时,窗口也会跟着改变。
在这里插入图片描述
在这里插入图片描述设计方法:
在这里插入图片描述

#include <iostream>
#include <vector>
//前置声明
class Observer;
//数据
class Subject{
private:
    int m_value;
    std::vector<Observer*> m_views;
public:
    void attach(Observer* objs){
        m_views.push_back(objs);
    }
    void setVal(int value){
        m_value = value;
        notify();
    }
    //直接在类内定义会报错:error: member access into incomplete type
    void notify();
};

//视图
class Observer{
public:
    virtual void update(Subject* subject,  int value) = 0;
};

void Subject::notify() {
    for(int i = 0;i < m_views.size();++i){
        m_views[i]->update(this, m_value);
    }
}

int main( ){

   return 0;
}

1.5.2 Composite设计模式【部分整体模式】

解决问题:文件系统,里面有文件夹或文件

案例:
在这里插入图片描述

//文件系统

#include <iostream>
#include <vector>
class Component{
public:
    Component(int data):m_data(data){}
    virtual void add(Component*){}
private:
    int m_data;
};
//文件
class Primitive:public  Component{
public:
    Primitive(int data):Component(data){}
};
//文件夹
class Composite:public Component{
public:
    Composite(int data):Component(data){}
    void add(Component* elem){m_p.push_back(elem);}
private:
    std::vector<Component*> m_p;

};

int main( ){

   return 0;
}

1.5.3 Prototype设计模式【原型模式】

作用:用于创建重复的对象,同时又能保证性能。

解决问题:创建未来才会出现的子类,让子类自己创建自己(原型),然后基类可以看见原型并复制它。

案例:
在这里插入图片描述

#include <iostream>
#include <vector>

enum imageType{
    LSAT,SPOT
};

class Image{
public:
    //发现和复制
    static  Image* findAndClone(imageType);
    virtual void draw() = 0;
    static void printNextSlot(){std::cout<<"m_nextSlot:"<<m_nextSlot<<std::endl;}
    virtual imageType  returnType() = 0;
protected:
    //用于子类返回类型
//    virtual imageType  returnType() = 0;
    //用于子类创建自己的原型
    virtual Image* clone() = 0;
    //添加原型
    static  void addProtoType(Image* image){
        m_protoTypes[m_nextSlot++] = image;
    }
private:
    static  int m_nextSlot;
    static Image* m_protoTypes[10];
};

Image* Image::m_protoTypes[];
int Image::m_nextSlot;

class LandSatImage: public Image{
public:
    imageType  returnType(){
        return LSAT;
    }
    void draw(){
        std::cout<<"LandSatImage::draw:"<<m_id<<std::endl;
    }
    //调用带参构造
    Image* clone(){
        return  new LandSatImage(1);
    }
protected:
    //避免addProtoType重复添加自己
    //只用于基类中的clone函数
    LandSatImage(int dummy){
        m_id = m_cout++;
    }

private:
    int m_id;
    static  int m_cout;
    static LandSatImage m_landSatImage;
    //调用静态的自己
    //默认构造
    LandSatImage(){
        std::cout<<"构造LandSatImage"<<std::endl;
        addProtoType(this);
    }
};
LandSatImage LandSatImage::m_landSatImage;
int LandSatImage::m_cout;

class SpotImage: public Image{
public:
    imageType  returnType(){return SPOT;}
    Image* clone(){ return new SpotImage(1);}
    void draw(){std::cout<<"SpotImage:draw:"<<m_id<<std::endl;}

protected:
    SpotImage(int dummy){
        m_id = m_cout++;
    }
private:
    int m_id;
    static  int m_cout;
    static SpotImage m_spotImage;
    SpotImage(){
    std::cout<<"构造SpotImage"<<std::endl;
    addProtoType(this);
    }
};
SpotImage SpotImage::m_spotImage;
int SpotImage::m_cout;


Image* Image::findAndClone(imageType type) {
    for(int i = 0;i < m_nextSlot;++i)
        if(m_protoTypes[i]->returnType() == type)
            return m_protoTypes[i]->clone();
}

int main( ){
    Image*  landSatImage =  Image::findAndClone(LSAT);
    Image* spotImage =  Image::findAndClone(SPOT);
    Image::printNextSlot();
    std::cout<<"type:"<<spotImage->returnType()<<std::endl;
   return 0;
}
相关推荐
©️2020 CSDN 皮肤主题: 岁月 设计师:pinMode 返回首页