How to implement classes derived from abstract using different methods?

I have implemented different classes derived from an abstract class, and each of them has different methods. The problem is that I have to declare the object only at runtime, so I need to create a pointer to the base class, and I cannot use the methods of each derived class.

I created an example to better explain what I mean:

#include <iostream>

using namespace std;

class poligon
{
public:
    double h, l;
    void setPoligon(double h, double l) {
        this->h = h;
        this->l = l;
    }
    virtual double GetArea() = 0;
    virtual void GetType() = 0;
};


class triangle : public poligon
{
    double GetArea() { return l*h / 2; }
    void GetType() { cout << "triangle" << endl; }
    double GetDiag() { return sqrt(l*l + h*h); }
};


class rectangle : public poligon
{
    double GetArea() { return l*h; }
    void GetType() { cout << "rectangle" << endl; }
};


void main()
{
    poligon* X;
    int input;

    cout << "1 for triangle and 2 for rectangle: ";
    cin >> input;

    if (input == 1)
    {
        X = new triangle;
    }
    else if (input == 2)
    {
        X = new rectangle;
    }
    else
    {
        cout << "Error";
    }

    X->h = 5;
    X->l = 6;

    X->GetType();
    cout << "Area = " << X->GetArea() << endl;

    if (input == 2)
    {
        cout << "Diangonal = " << X->GetDiag() << endl;    // NOT POSSIBLE BECAUSE " GetDiag()" IS NOT A METHOD OF "poligon" CLASS !!!
    }
}

Obviously, the method X->GetDiag()at the end of main cannot be used because it is not a method of the poligon class. What is the correct implementation of a program with this logic?

+4
source share
7 answers

Introduce a method into a base class

virtual bool boHasDiagonal(void) =0;

:

virtual double GetDiag();

- :

virtual bool boHasDiagonal(void) {return true;} // rectangle
virtual bool boHasDiagonal(void) {return false;} // triangle

:

if (X->boHasDiagonal())
{cout << "Diangonal = " << X->GetDiag() << endl;}

( , ), Gluttton GetDiag(), ( ).

Rakete1111 .

+3

, :

class poligon
{
public:
    virtual double GetDiag()
    {
        throw std::logic_error ("Called function with inappropriate default implementation.");
    }
};

, , :

class rectangle : public poligon
{
    double GetDiag() override
    {
        return diagonale;
    }
};

:

int main () {
    try {
        X->GetDiag();
    }
    catch (...) {
        std::cout << "Looks like polygon doesn't have diagonal." << std::endl;
    }
}
+1

dynamic_cast.

dynamic_cast<triangle*>(X)->GetDiag();

, : triangle if input == 1, , input == 2. , , dynamic_cast nullptr, .

, dynamic_cast , input == 2:

if (triangle* tri = dynamic_cast<triangle*>(X))
    std::cout << "Diagonal = " << tri->GetDiag() << '\n';
0

dynamic_cast -. nullptr, . , :

triangle* R = dynamic_cast<triangle*>(X);
if(R) {
    cout << "Diagonale = " << R->GetDiag() << '\n';
};

: if-, if-statement:

if(triangle* R = dynamic_cast<triangle*>(X)) {
    cout << "Diagonale = " << R->GetDiag() << '\n';
};

if(rectangle* R = ...) {...}; // reuse of identifier

, multiple subclasses GetDiag, poligon diagonal. diagonal GetDiag polygon:

class polygon {
    // stays the same
};

class diagonal {
    virtual double GetDiag() = 0;
};

class triangle : public polygon, public diagonal {
    // body stays the same
};

, , dynamic_cast, diagonal. , poligon diagonal, .

   polygon         diagonal
    |   |             |
    |   |_____________|
    |          |
    |          |
rectangle   triangle
0

, , , :

int main()
{
    ...
    if(triangle* t = dynamic_cast<triangle*>(X))
        std::cout << "Triangle diagonal = " << t->GetDiag() << std::endl;
    return 0;
}

PS: , - , .

0

, dynamic_cast , - - . , . , , . , . , dynamic_cast .

, . , , . , , ( ), .

class poligon
{
public:
    double h, l;
    void setPoligon(double h, double l) {
        this->h = h;
        this->l = l;
    }
    virtual double GetArea() = 0;
    virtual void GetType() = 0;
};


class triangle : public poligon
{
    double GetArea() { return l*h / 2; }
    void GetType() { cout << "triangle" << endl; }
    double GetDiag() { return sqrt(l*l + h*h); }
};

, . . ? . , ? , , .. , .

There are several solutions, but since this is a design issue, the decision depends on what you want to do with the objects.

0
source

Knockback is usually a sign of poor construction and rarely required in practice.

I do not understand why this is necessary in this particular case. You dropped information about what type you have for no reason. An alternative could be:

void printDiagonal(const triangle& tri)
{
    std::cout << "Diangonal = " << tri.GetDiag() << std::endl;
}

void process(poligon& p)
{
    p.h = 5;
    p.l = 6;

    p.GetType();
    std::cout << "Area = " << p.GetArea() << std::endl;
}

int main()
{
    int input;

    std::cout << "1 for triangle and 2 for rectangle: ";
    std::cin >> input;

    if (input == 1)
    {
        triangle tri;
        process(tri);
        printDiagonal(tri);
    }
    else if (input == 2)
    {
        rectangle rect;
        process(rect);
    }
    else
    {
        std::cout << "Error\n";
    }
}

Live demo .

0
source

Source: https://habr.com/ru/post/1684970/


All Articles