1

Тема: Поліморфізм

Привіт.
Задача

Прихований текст

Спроектувати (нарисувати) і реалізувати ієрархію класів, що описують предметну область «Мутант» (CMutant), що був отриманий шляхом схрещування пса Бобіка (описується класом CDog) і свині Хрюші (описується класом CPig). Класи CDog і CPig мають спільний батьківський клас CAnimal. Додаткові вимоги:
1.    Базовий клас містить мінімум одну віртуальну функцію (наприклад, яка виводить на екран текстом звук, який видає тваринка).
2.    Забезпечити механізми коректної роботи конструкторів і деструкторів.
3.    Перевантажити operator = з метою його коректної роботи.
4.    Кожен з класів має містити мінімум один член даних і 4 функції-члени.
5.    Написати main() функцію де створити об’єкт класу CMutant і продемонструвати різницю між статичним і динамічним поліморфізмом.

Ось моє вирішення!

"mutant.h"

class CAnimal {
protected:
    char *name;
public:
    CAnimal();
    CAnimal(const CAnimal&);
    CAnimal(const char*);
    virtual ~CAnimal();
    virtual void call();
    virtual void massage();
};

class CDog: virtual public CAnimal {
protected:
    char *language;
public:
    CDog();
    CDog(const CDog&);
    CDog(const char*);
    void operator=(const CDog*);
    void call();
    void massage();
    void setLanguage(const char*);
    const char *getLanguage();
    virtual ~CDog();
};

class CPig: virtual public CAnimal {
protected:
    char *lag;
public:
    CPig();
    CPig(const char*);
    CPig(const CPig&);
    void operator=(const CPig&);
    virtual void call();
    virtual void massage();
    void setlag(const char*);
    const char *getlag();
    virtual ~CPig();
};

class CMutant: public CPig, public CDog
{
private:
    char *mass;
public:
    CMutant();
    CMutant(const char*);
    CMutant(const CMutant&);
    ~CMutant();
    void operator=(const CMutant&);
    void call();
    void massage();
    const char *getMassage();
    void setMassage(const char*);
};

"mutant.cpp"

#include "mutant.h"
#include <cstring>
#include <iostream>
using namespace std;

CAnimal::CAnimal() {
    name = new char[128];
}

CAnimal::CAnimal(const CAnimal &that) {
    name = new char[128];
    strcpy(name, that.name);
}

CAnimal::CAnimal(const char *init_name) {
    name = new char[128];
    strcpy(name, init_name);
}

CAnimal::~CAnimal() {
    delete[] name;
}

void CAnimal::call() {
    cout << "Name  " << name <<endl;
}

void CAnimal::massage() {
    cout << "prosto text dlya kilkosti "<<endl;
}

CDog::CDog() {
    language = new char[128];
    strcpy(name, "sobaka ");
    strcpy(language, "gav gav ");
}

CDog::CDog(const CDog& that) {
    language = new char[128];
    strcpy(name, that.name);
    strcpy(language, that.language);
}

CDog::CDog(const char *initName) {
    language = new char[128];
    strcpy(name, initName);
    strcpy(language, "gav gav ");
}

void CDog::call() {
    cout << "sobaka " << name << '\t' << language << endl;
}

void CDog::massage() {
    cout << "gav gav gav"<<endl ;
}

void CDog::operator=(const CDog *that) {
    strcpy(this->name, that->name);
    strcpy(this->language, that->language);
}

void CDog::setLanguage(const char *init_lang) {
    strcpy(language, init_lang);
}

const char *CDog::getLanguage() {
    return language;
}

CDog::~CDog() {
    delete[] language;
}

CPig::CPig() {
    lag = new char[128];
    strcpy(name, "svinia ");
    strcpy(lag, "4");
}

CPig::CPig(const char *init_name) {
    lag = new char[128];
    strcpy(name, init_name);
    strcpy(lag, "4");
}

CPig::CPig(const CPig &that) {
    strcpy(this->name, that.name);
    strcpy(this->lag, that.lag);
}

void CPig::call() {
    cout << "admin\t" << name << '\t' << lag << '\n';
}

void CPig::massage() {
    cout << "i have lag"<<endl;
}

void CPig::setlag(const char* init_lag) {
    strcpy(lag, init_lag);
}

void CPig::operator=(const CPig &that) {
    strcpy(this->name, that.name);
    strcpy(this->lag, that.lag);
}

const char *CPig::getlag() {
    return lag;
}

CPig::~CPig() {
    delete[] lag;
}

CMutant::CMutant() {
    mass = new char[128];
    strcpy(mass, "my massage");
}

CMutant::CMutant(const char *init_massage) {
    mass = new char[128];
    strcpy(mass, init_massage);
}

void CMutant::call() {
    cout << "animal " << name << '\t' << lag << '\t'
        << language << '\t' << mass << '\n';
}

void CMutant::massage() {
    cout << mass << '\n';
}

void CMutant::setMassage(const char *init_massage) {
    strcpy(mass, init_massage);
}

const char *CMutant::getMassage() {
    return mass;
}

void CMutant::operator=(const CMutant &that) {
    strcpy(this->name, that.name);
    strcpy(this->mass, that.mass);
    strcpy(this->lag, that.lag);
    strcpy(this->language, that.language);
}

CMutant::~CMutant() {
    delete[] mass;
}

"main.cpp"

#include "mutant.h"
#include <iostream>
using namespace std;

int main() {
    CAnimal *a[4];
    a[0] = new CMutant("m");
    a[1] = new CDog("sobaka ");
    a[2] = new CPig("svinia");
    a[3] = new CAnimal("a");

    a[0]->call();
    a[1]->call();
    a[2]->call();
    a[3]->call();


    delete a[0];
    delete a[1];
    delete a[2];
    delete a[3];


    return 0;
}

Хто знається, гляньте код!
Він працює, але чи правильно(коректно)?
Бо сам до кінця не усвідомлюю всіх тонкощів, оскільки писав по прикладу з книги!

продемонструвати різницю між статичним і динамічним поліморфізмом.

Це також присутнє, але не певен чи належним чином!

2

Re: Поліморфізм

Аналіз нашвидкуруч:
1. Клас Animal, по-хорошому, мав би бути абстрактним, тож йому не завадив би який-небудь чисто віртуальний метод (деструктор, наприклад).

2.

virtual void massage();
Прихований текст

http://174.120.21.187/~tlc/wp-content/uploads/2012/03/Massage-Therapist-and-Client_full.jpg

3.

void operator=(const CPig&);
//і подібні йому в інших класах

Чому ви вирішили, що він вертає void?

T& operator = (T obj)
{
//some actions...
  return *this;
}

4.

class CMutant: public CPig, public CDog

Ключові граблі. У вас є два класи, що спадкуються від одного з перевантаженням методів батька. А від них спадкується ще один, який набуває методів своїх батьків, причому назва цих методів буде однакова. А який викликати?..
Ці граблі звуться діамантовим спадкуванням.
Тому

class CMutant: virtual public CPig, virtual public CDog

5. Щодо поліморфізму тут:
Віртуальними методами ви досягли ресурсів для динамічного поліморфізму.
Тепер, коли ви створюєте покажчик на базовий клас, а під ним виділяєте місце для класу-дитини, буде динамічний поліморфізм. Якщо цей покажчик напряму є типу класу-дитини, маєте статичний (тип відомий на етапі компіляції).

6.

Ви точно це мали на увазі?:)
wikipedia написав:

Lag is a common word meaning to fail to keep up or to fall behind.[1] In real-time applications, the term is used when the application fails to respond in a timely fashion to inputs.

3

Re: Поліморфізм

3.

   

 void operator=(const CPig&);
    //і подібні йому в інших класах

Чому ви вирішили, що він вертає void?

   

 T& operator = (T obj)
    {
    //some actions...
    return *this;
    }

Тобто для кожний перезавантажений оператор повинен щось повертати?

Щодо 6 пункту то leg ( ноги), можна paws ( лапи)
Та тут різниці немає!


Дякую за аналіз!

4

Re: Поліморфізм

Anddep написав:

Тобто для кожний перезавантажений оператор повинен щось повертати?

ну, коли відбувається, наприклад, додавання двох integer, то повертається значення теж integer - тут те саме, тільки оператор унарний

5

Re: Поліморфізм

Cyan написав:
Anddep написав:

Тобто для кожний перезавантажений оператор повинен щось повертати?

ну, коли відбувається, наприклад, додавання двох integer, то повертається значення теж integer - тут те саме, тільки оператор унарний

Власне кажучи, повернути можна що завгодно, навіть ніщо void. :)
Однак дядько Півнесмерть (Страуструп) постановив, що оператори у певних ситуаціях мусять дотримуватися чітко визначеного шаблону, інакше на програму впаде кара.

Приклад
#include <cstdio>

#define INT_DEBUG 0

class A
{
    double x;

public:
    A():x(0){}

#if INT_DEBUG != 0
    int operator = (A& a)
    {
        printf("Operator returns %d\n", (int)(x/a.x));
        return (int)(x/a.x);
    }
#else
    A operator = (A a)
    {
        x=a.x+1;
        printf("Operator returns an object of A with x=%3.2lf\n",x);
        return *this;
    }
#endif    
    double X()const
    {return x;}
};

int main()
{
    A a1;
    A a2;
    a2 = a1;
    printf("1 - %lf;\n2 - %lf\n", a1.X(), a2.X());
}

Нижче наведені результати використання кожного з варіантів оператора "=".

Результат для нормального випадку (INT_DEBUG 0)

http://osidok.pp.ua/images/2013/04/21/0.png

А от приклад "єресі"

http://osidok.pp.ua/images/2013/04/21/1.png

Як щось незрозуміло - питання в студію. :)

6

Re: Поліморфізм

В принципі, зрозуміло!
Але для мого випадку

CDog::operator=(const CDog *that) {
    strcpy(this->name, that->name);
    strcpy(this->language, that->language);
  return *this;}

???

7

Re: Поліморфізм

Anddep написав:

В принципі, зрозуміло!
Але для мого випадку

CDog::operator=(const CDog *that) {
    strcpy(this->name, that->name);
    strcpy(this->language, that->language);
  return *this;}

???

CDog CDog::operator=(CDog that) {
    strcpy(this->name, that.name);
    strcpy(this->language, that.language);
  return *this;}

З.І: У cpp-файлах спочатку підключайте стандартні заголовки, а потім вже власні. ;)

8 Востаннє редагувалося Anddep (23.04.2013 17:44:47)

Re: Поліморфізм

Ось те, що зробив!
Вроді працює коректно


Ось моє вирішення!

"mutant.h"
class CAnimal {
protected:
    char *name;
public:
    CAnimal();
    CAnimal(const CAnimal&);
    CAnimal(const char*);
    virtual ~CAnimal();
    void call();
    virtual void printMassage();
    void setName(const char*);
};

class CDog: virtual public CAnimal {
protected:
    char *language;
public:
    CDog();
    CDog(const CDog&);
    CDog(const char*name,const char*language);
    CDog operator=(const CDog*);
    void call();
    void printMassage();
    void setLanguage(const char*);
    const char *getLanguage();
    virtual ~CDog();
};

class CPig: virtual public CAnimal {
protected:
    char *lag;
public:
    CPig();
    CPig(const char*name,const char*lag);
    CPig(const CPig&);
    CPig operator=(const CPig&);
    void call();
    virtual void printMassage();
    void setlag(const char*);
    const char *getlag();
    virtual ~CPig();
};

class CMutant: virtual public CPig, virtual public CDog{
private:
    char *mass;
public:
    CMutant();
    CMutant(const char*name,const char*lag,const char*language,const char*mass);
    CMutant(const CMutant&);
    ~CMutant();
    CMutant operator=(const CMutant&);
    void call();
    void printMassage();
    const char *getMassage();
    void setMassage(const char*);
    
};
"mutant.cpp"
#include <cstring>
#include <iostream>
#include "mutant.h"
using namespace std;

CAnimal::CAnimal() {
    name = new char[1];
}

void CAnimal::setName(const char* str) {
    delete[] name;
    name = new char[strlen(str)+1];
    strcpy(name, str);
}
CAnimal::CAnimal(const CAnimal &that) {
    name = new char[strlen(that.name)+1];
    strcpy(name, that.name);
}

CAnimal::CAnimal(const char *init_name) {
    
    name = new char[128];
    strcpy(name, init_name);
}

CAnimal::~CAnimal() {
    delete[] name;
}

void CAnimal::call() {
    cout << "Animal's name " << name <<endl;
}

void CAnimal::printMassage() {
    cout << "Animal's name " << name <<endl;
}

CDog::CDog() {
    language = new char[128];
    strcpy(name, "sobaka ");
    strcpy(language, "gav gav ");
}

CDog::CDog(const CDog& that) {
    delete[] language;
    language = new char[128];
    strcpy(name, that.name);
    strcpy(language, that.language);
}

CDog::CDog(const char *name,const char *language): CAnimal(name) {
    this->language = new char[128];
    strcpy(this->language, language);
}

void CDog::call() {
    CAnimal::printMassage();
    cout << "gav gav gav"<<endl;
}

void CDog::printMassage() {
    CAnimal::printMassage();
    cout << "gav gav gav"<<endl ;
}

CDog CDog::operator=(const CDog *that) {
    strcpy(this->name, that->name);
    strcpy(this->language, that->language);
    return *this;
}

void CDog::setLanguage(const char *init_lang) {
    strcpy(language, init_lang);
}

const char *CDog::getLanguage() {
    return language;
}

CDog::~CDog() {
    delete[] language;
}

CPig::CPig() {
    lag = new char[128];
    strcpy(name, "svinia ");
    strcpy(lag, "4");
}

CPig::CPig(const char *init_name,const char *lag) : CAnimal(init_name) {
    this->lag = new char[128];
    strcpy(this->lag, lag);
}

CPig::CPig(const CPig &that) {
    strcpy(this->name, that.name);
    strcpy(this->lag, that.lag);
}

void CPig::call() {
    CAnimal::printMassage();
    cout << "lags: " << lag<<endl;
}

void CPig::printMassage() {
    CAnimal::printMassage();
    cout << "lags: " << lag<<endl;
}

void CPig::setlag(const char* init_lag) {
    strcpy(lag, init_lag);
}

CPig CPig::operator=(const CPig &that) {
    strcpy(this->name, that.name);
    strcpy(this->lag, that.lag);
    return *this;
}

const char *CPig::getlag() {
    return lag;
}

CPig::~CPig() {
    delete[] lag;
}

CMutant::CMutant() {
    mass = new char[128];
    strcpy(mass, "my massage");
}

CMutant::CMutant(const char *name,const char*lag,const char*language,const char*mass):CPig(name,lag),CDog(name,language), CAnimal(name) {
    this->mass = new char[128];
    strcpy(this->mass, mass);
}

void CMutant::call() {
    CAnimal::printMassage();
    cout << "lang: "<< language << " lag: " <<lag <<" mass "<< mass << '\n';
}

void CMutant::printMassage() {
    CAnimal::printMassage();
    cout << "lang: "<< language << " lag: " <<lag <<" mass "<< mass << '\n';
}

void CMutant::setMassage(const char *init_massage) {
    strcpy(mass, init_massage);
}

const char *CMutant::getMassage() {
    return mass;
}

CMutant CMutant::operator=(const CMutant &that) {
    strcpy(this->name, that.name);
    strcpy(this->mass, that.mass);
    strcpy(this->lag, that.lag);
    strcpy(this->language, that.language);
    return *this;
}

CMutant::~CMutant() {
    delete[] mass;
}
CMutant::CMutant(const CMutant&){
}
"main.cpp"
#include "mutant.h"
#include <iostream>
#include "mutant.h"
using namespace std;

int main() {

    CAnimal *a[4];
    a[0] = new CMutant("Animals"," 2 or 4 ", "gav or hru ","mova");
    a[1] = new CDog("sobaka ","dd");
    a[2] = new CPig("svinia","4");
    a[3] = new CAnimal("Mutant");

    a[0]->printMassage();
    a[1]->printMassage();
    a[2]->printMassage();
    a[3]->printMassage();
    cout<<endl<<endl;
    a[0]->call();
    a[1]->call();
    a[2]->call();
    a[3]->call();

    delete a[0];
    delete a[1];
    delete a[2];
    delete a[3];

    return 0;
}
}

9

Re: Поліморфізм

За спойлер - дякую, та ще тег code всередині спойлера додайте. :)

І ще момент:

virtual public спадкування логічне лише для Мутанта, оскільки у нього можуть виникнути оказії з іменами успадкованих генів полів та методів. Однак самі Свиня та Собака мають спадкуватися безпосередньо public: у них нема такої колізії.