Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is benifit of making a class abstract

Let's take an example,

class base{
public:
virtual void abstract() = 0;
};

class derived:public base{
public:
void abstract(){cout << "Abstract\n";}
};

int main{
derived d;
d.abstract();
return 0;
}

It can be written in other way as,

class base{
    public:
    void abstract(){cout << "Abstract\n";}
    };

    int main{
    base b;
    b.abstract();
    return 0;
    }

It is also providing same result, infact here I don't need to derive the class. I did read many article on abstract class, it says we can not instantiate base class and a pure virtual function forces user to define the function. But if we will see the above code in both the cases I am getting same result (or output). So here my question is how abstract classes helps us?

like image 989
Rasmi Ranjan Nayak Avatar asked Apr 17 '13 11:04

Rasmi Ranjan Nayak


3 Answers

As you've noticed, in your example code there is no point having separate base and derived classes.

In general, the purpose of classes with virtual functions is dynamic polymorphism, but your code hasn't used it.

Suppose you had some code that used a base* without knowing which (of several) derived classes it actually points to. Suppose that they each have different implementations of abstract(). Suppose that you want to force anyone who writes a derived class of base to implement their own version of abstract(). Then there's a reason to make abstract() a pure virtual function and hence a reason for base to be an abstract class:

#include <iostream>
#include <cstdlib>
#include <ctime>

struct Base {
    virtual void abstract() = 0;
    virtual ~Base() {};
};

struct Derived1 : Base {
    void abstract() { std::cout << "Derived1\n"; }
};

struct Derived2 : Base {
    void abstract() { std::cout << "Derived2\n"; }
};

Base *random_object() {
    if (std::rand() < RAND_MAX/2) {
        return new Derived1();
    } else {
        return new Derived2();
    }
}

int main() {
    std::srand(std::time(0));
    Base *b = random_object();
    b->abstract();
    delete b;
}

The code in main only cares about Base, it doesn't need to know anything about derived classes beyond the fact that there might be some. Only the code in random_object knows about the derived classes. Meanwhile Base doesn't need to know how abstract() is implemented, only the derived classes do (and each one only cares about its own implementation). It's good for code not to need to know about things -- it means those things can be changed without touching the code that doesn't care.

There are also some high-level design issues around using a non-abstract class as a public base class. For example, it's quite easy to unthinkingly write code that won't work as you expect once some of your functions have been overridden, and it's quite easy to accidentally slice an object with a concrete base class. So there's a philosophy that says you should know at all times whether you're writing a concrete class or a base class, and not try to do both at once. When you follow this philosophy, all base classes are abstract, so you make a class abstract to signal that it is designed to be derived from.

like image 195
Steve Jessop Avatar answered Sep 24 '22 13:09

Steve Jessop


Abstract classes are used to provide an interface for some functionality, where the exact behaviour is defined by the caller's class. To ensure that the "user" of the function implements their functions, you use abstract functions in the base-class. That way, if the "user" doesn't provide one of the required functions, the code doesn't compile.

like image 29
Mats Petersson Avatar answered Sep 24 '22 13:09

Mats Petersson


Here's an example for you: Let's say your program needs to calculate the area of different shapes.

class shape{
public:
    virtual double area() = 0;
};

class triangle:public shape{
public:
    triangle(double base, double height) : b(base), h(height) {}
    double area(){ return 0.5 * b * h; }
private:
    double b;
    double h;
};

class circle:public shape{
public:
    circle(double radius) : r(radius) {}
    double area(){ return M_PI * r * r; }
private:
    double r;
};

int main{
    std::vector<shape*> shapes;

    //add whatever shapes you want here
    shapes.push_back( new triangle(4, 5) );
    shapes.push_back( new circle(3) );

    double dTotal = 0.0;
    std::vector<shape*>::iterator i;
    for (i = shapes.begin(); i != shapes.end(); i++)
    {
        dTotal += (*i)->area();
        delete *i;
    }

    cout << dTotal;
    return 0;
}

You could now very easily create shapes for rectangle, circle, dodecahedron, etc and treat them all similarly without knowing the specifics of how they compute their own areas. At the same time, it doesn't make sense for shape to define an area of its own.

EDIT: added another derived class and made use of them using the abstract method.

like image 27
metalhead Avatar answered Sep 23 '22 13:09

metalhead