C++重点和练习-----多态

发布于:2024-12-18 ⋅ 阅读:(34) ⋅ 点赞:(0)

rpg.cpp:

#include <iostream>

using namespace std;


/*
    模拟一个游戏场景
    有一个英雄:初始所有属性为1
    atk,def,apd,hp

    游戏当中有以下3种武器
    长剑Sword: 装备该武器获得 +1atx,+1def
    短剑Blade: 装备该武器获得 +1atk,+1spd
    斧头Axe:   装备该武器获得 +1atk,+1hp

    要求英雄写一个函数:
    equipweapon 装备武器
    实现效果:装备不同武器英雄获得不同的属性加成
*/

class Hero;

class Weapon
{
    int atk;
public:
    Weapon():atk(1){}
    virtual ~Weapon(){}
    void set_atk(int atk)
    {
        this->atk = atk;
    }
    int get_atk()
    {
        return atk;
    }
    virtual void equip(Hero &h);
};

class Sword:public Weapon
{
    int def;
public:
    Sword():def(1){}
    void set_def(int def)
    {
        this->def = def;
    }
    int get_def()
    {
        return def;
    }
    void equip(Hero &h) override;
};

class Blade:public Weapon
{
    int spd;
public:
    Blade():spd(1){}
    void set_spd(int spd)
    {
        this->spd = spd;
    }
    int get_spd()
    {
        return spd;
    }
    void equip(Hero &h) override;
};

class Axe:public Weapon
{
    int hp;
public:
    Axe():hp(1){}
    void set_hp(int hp)
    {
        this->hp = hp;
    }
    int get_hp()
    {
        return hp;
    }
    void equip(Hero &h) override;
};

class Hero
{
    int atk;
    int def;
    int spd;
    int hp;
    Weapon * current_weapon;
public:
    Hero():atk(1),def(1),spd(1),hp(1),current_weapon(new Weapon){}
    ~Hero(){delete current_weapon;}
    void set_atk(int atk)
    {
        this->atk = atk;
    }
    int get_atk()
    {
        return atk;
    }
    void set_def(int def)
    {
        this->def = def;
    }
    int get_def()
    {
        return def;
    }
    void set_spd(int spd)
    {
        this->spd = spd;
    }
    int get_spd()
    {
        return spd;
    }
    void set_hp(int hp)
    {
        this->hp = hp;
    }
    int get_hp()
    {
        return hp;
    }
    void equip_weapon(Weapon *w);
    void show();
};

void Weapon::equip(Hero &h)
{
    int new_atk = h.get_atk() + this->get_atk();
    h.set_atk(new_atk);
}

void Sword::equip(Hero &h)
{
    Weapon::equip(h);
    int new_def = h.get_def() + def;
    h.set_def(new_def);
}

void Blade::equip(Hero &h)
{
    Weapon::equip(h);
    int new_spd = h.get_spd() + spd;
    h.set_spd(new_spd);

}

void Axe::equip(Hero &h)
{
    Weapon::equip(h);
    int new_hp = h.get_hp() + hp;
    h.set_hp(new_hp);
}

void Hero::equip_weapon(Weapon *w)
{
    delete current_weapon;
    current_weapon = w;
    w->equip(*this);

}

void Hero::show()
{
    cout << "******** 英雄属性 ********" << endl
         << "  " << "atk = " << atk << endl
         << "  " << "def = " << def << endl
         << "  " << "spd = " << spd << endl
         << "  " << "hp = \t" << hp << endl
         << "**************************" << endl;
}

int main()
{
    Hero h1,h2,h3;
    h1.equip_weapon(new Sword);
    h2.equip_weapon(new Blade);
    h3.equip_weapon(new Axe);
    h1.show();
    h2.show();
    h3.show();


    return 0;
}

通过虚函数解决菱形继承产生的二义性问题

    A       --------公共基类
  /   \
 B     C    --------中间子类
  \   /
    D       --------汇集子类
B类中会继承A类的成员,C类中也继承A类的成员,
D类中汇集成B和C中的所有成员 ------>导致A类中的内容,在D类中存在两份
有可能造成代码膨胀
#include <iostream>
using namespace std;
class A
{
public:
    int a;
    A():a(9){cout << "A构造" << endl;}
};
class B:public A
{
public:
    int b;
    B():b(0){cout << "B构造" << endl;}
};
class C:public A
{
    int c;
public:
    //因为继承顺序是先继承B,再继承A,所以B先构造结束,后A构造结束,最后C构造结束
    //和初始化列表中的调用顺序无关
    C():c(6),A(){cout << "C构造" << endl;}
    void show();
};
class D:public B,public C
{
    void show_a()
    {
        //cout << a << endl;   //因为中间基类中存在两种方式可以找到a
        cout << B::a << endl;  //存在于B类中的A类继承下来的a
        cout << C::a << endl;  //存在于C类中的A类继承下来的a
    }
};
int main()
{
    C c1;
    c1.show();
    return 0;
}

 虚继承(virtual)

#include <iostream>

using namespace std;


class Person
{
    int age;                //4字节
    string name;            //32字节 +4对齐 36
public:
    Person(){}
    Person(int age,string name):age(age),name(name){}
    virtual void show();    //虚指针 8字节
};                          //48

class Stu:public Person     // 继承Person 48
{
    double score;           //56
public:
    Stu(){}
    Stu(int age,string name,double score):Person(age,name),score(score){}
    void show();            //对虚指针指向的虚函数表中的show进行重写
};                          //56

void Person::show()
{
    cout << "Person 中的show函数 " << endl;
    cout << "age = " << age << endl;
    cout << "name = " << name << endl;
}

void Stu::show()
{
    cout << "Stu 中的show函数 " << endl;
    cout << "score = " << score << endl;
}

int main()
{
    cout << sizeof (Person) << endl;
    cout << sizeof (Stu) << endl;
    Stu s1(18,"张三",99);
    Person &rp = s1;
    rp.show();
    rp.Person::show();
    return 0;
}

在菱形继承中,由于汇集子类中会保存两份公共基类的内容造成二义性问题,所以通常两个中间子类会虚继承公共基类 ------>在汇集子类中就只存在一份公共基类的内容

#include <iostream>
using namespace std;
class A
{
public:
    int a;
    A():a(9){cout << "A构造" << endl;}
};
//中间子类虚继承公共基类A
class B:virtual public A
{
public:
    int b;
    B():b(0),A(){cout << "B构造" << endl;}
};
class C:virtual public A
{
    int c;
public:
    //因为继承顺序是先继承B,再继承A,所以B先构造结束,后A构造结束,最后C构造结束
    //和初始化列表中的调用顺序无关
    C():c(6),A(){cout << "C构造" << endl;}
    void show();
};
class D:public B,public C
{
    //汇集子类的构造函数中对于公共基类的构造,需要直接调用公共基类的构造函数即可
    D():B(),C(),A(){}
    void show_a()
    {
        //不加virtual,有两份A中的a
        cout << a << endl;   //由于我们使用了虚继承,所以D类中只有一份从公共基类中继承下来的a
        cout << B::A::a << endl;
        cout << C::A::a << endl;
    }
};
int main()
{
    C c1;
    c1.show();
    return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到