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?
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With