纯虚拟函数(二)


在定义类时,可以完全只有纯虚拟函数,完全不提供实现,也没有任何状态定义,将类当成是一种行为规范。

来个简单的需求演变情境,以说明为什么要有这种类。老板今天想开发一个海洋乐园游戏,当中所有东西都会游泳。你想了一下,谈到会游的东西,第一个想到的就是鱼,你也许会定义Fish类有个swim的行为:

class Fish {
protected:
    string name;

public:
    Fish(string name) : name(name) {}

    string getName() {
        return this->name;
    }

    virtual void swim() = 0;
};

由于实际上每种鱼游泳方式不同,所以将swim定义为纯虚拟函数,因此Fish是抽象类。接着定义小丑鱼继承各种鱼:

class Fish : public Swimmer {
protected:
    string name;

public:
    Fish(string name) : name(name) {}

    string getName() {
        return this->name;
    }
};

class Anemonefish : public Fish {
public:
    using Fish::Fish;

    void swim() override {
        cout << "小丑鱼 " + this->name + " 游泳" << endl; 
    }
};

class Shark : public Fish {
public:
    using Fish::Fish;

    void swim() override {
        cout << "鲨鱼 " + this->name + " 游泳" << endl; 
    }
};

class Piranha : public Fish {
public:
    using Fish::Fish;

    void swim() override {
        cout << "食人鱼 " + this->name + " 游泳" << endl; 
    }
};

老板说话了,为什么都是鱼?人也会游泳啊!怎么没写?于是你就再定义Human类继承Fish…等一下!Human继承Fish? 不会觉得很奇怪吗?人是一种鱼吗?既然如此,不如将Fish改名为Swimmer,让Human继承Swimmer,这样好像说得过去,鱼是一种会游泳的生物,人也是一种会游泳的生物嘛!

不过,如果Human要有firstNamelastName两个值域呢?也就是说就算你将Fish改名为Swimmer,原本的状态定义,并不适合Human来继承,怎么办呢?

既然都想要抽象的swim,而状态不同是个问题,不如就定义个没有状态的Swimmer吧!

class Swimmer {
public:
    virtual void swim() = 0;
    virtual ~Swimmer() = default;
};

然后原本的Fish继承Swimmer

class Fish : public Swimmer {
protected:
    string name;

public:
    Fish(string name) : name(name) {}

    string getName() {
        return this->name;
    }
};

Fish方才的子类不用修改,也就是维持既有的继承体系,接着Human也可以继承Swimmer

class Human : public Swimmer {
protected:
    string firstName;
    string lastName;

public:
    Human(string firstName, string lastName) : 
        firstName(firstName), lastName(lastName) {}

    string getFirstName() {
        return this->firstName;
    }

    string getLastName() {
        return this->lastName;
    }

    void swim() override {
        cout << "人类 " + this->firstName + " " + this->lastName + " 游泳" << endl; 
    }
};

那来个潜水艇吧!

class Submarine : public Swimmer {
protected:
    string nickName;

public:
    Submarine(string nickName) : nickName(nickName) {}

    string getNickName() {
        return this->nickName;
    }

    void swim() override {
        cout << "潜水艇 " + this->nickName + " 潜行" << endl; 
    }
};

现在,大家可以快快乐乐地一起游泳了:

...略

void doSwim(Swimmer &swimmer) {
    swimmer.swim();
}

int main() { 
    Anemonefish anemonefish("尼莫");
    Shark shark("兰尼");
    Human human("贾斯汀", "林");
    Submarine submarine("黄色一号");

    doSwim(anemonefish);
    doSwim(shark);
    doSwim(human);
    doSwim(submarine);

    return 0;
}

执行结果如下:

小丑鱼 尼莫 游泳
鲨鱼 兰尼 游泳
人类 贾斯汀 游泳
潜水艇 黄色一号 潜行
小丑鱼 尼莫 游泳
鲨鱼 兰尼 游泳
人类 贾斯汀 林 游泳
潜水艇 黄色一号 潜行




展开阅读全文