Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't we create objects for an abstract class in C++?

I know it is not allowed in C++, but why? What if it was allowed, what would the problems be?

like image 640
Moeb Avatar asked Jan 19 '10 05:01

Moeb


4 Answers

Judging by your other question, it seems you don't understand how classes operate. Classes are a collection of functions which operate on data.

Functions themselves contain no memory in a class. The following class:

struct dumb_class
{
    void foo(){}
    void bar(){}
    void baz(){}
    // .. for all eternity

    int i;
};

Has a size of int. No matter how many functions you have ever, this class will only take up the space it takes to operate on an int. When you call a function in this class, the compiler will pass you a pointer to the place where the data in the class is stored; this is the this pointer.

So, the function lie in memory somewhere, loaded once at the beginning of your program, and wait to be called with data to operate on.

Virtual functions are different. The C++ standard does not mandate how the behavior of the virtual functions should go about, only what that behavior should be. Typically, implementations use what's called a virtual table, or vtable for short. A vtable is a table of function pointers, which like normal functions, only get allocated once.

Take this class, and assume our implementor uses vtables:

struct base { virtual void foo(void); };
struct derived { virtual void foo(void); };

The compiler will need to make two vtables, one for base and one for derived. They will look something like this:

typedef /* some generic function pointer type */ func_ptr;

func_ptr __baseTable[] = {&base::foo}; 
func_ptr __derivedTable[] = {&derived::foo}; 

How does it use this table? When you create an instance of a class above, the compiler slips in a hidden pointer, which will point to the correct vtable. So when you say:

derived d;
base* b = &d;
b->foo();

Upon executing the last line, it goes to the correct table (__derivedTable in this case), goes to the correct index (0 in this case), and calls that function. As you can see, that will end up calling derived::foo, which is exactly what should happen.

Note, for later, this is the same as doing derived::foo(b), passing b as the this pointer.

So, when virtual methods are present, the class of the size will increase by one pointer (the pointer to the vtable.) Multiple inheritance changes this a bit, but it's mostly the same. You can get more details at C++-FAQ.

Now, to your question. I have:

struct base { virtual void foo(void) = 0; }; // notice the = 0
struct derived { virtual void foo(void); };

and base::foo has no implementation. This makes base::foo a pure abstract function. So, if I were to call it, like above:

derived d;
base* b = &d;
base::foo(b);

What behavior should we expect? Being a pure virtual method, base::foo doesn't even exist. The above code is undefined behavior, and could do anything from nothing to crashing, with anything in between. (Or worse.)

Think about what a pure abstract function represents. Remember, functions take no data, they only describe how to manipulate data. A pure abstract function says: "I want to call this method and have my data be manipulated. How you do this is up to you."

So when you say, "Well, let's call an abstract method", you're replying to the above with: "Up to me? No, you do it." to which it will reply "@#^@#^". It simply doesn't make sense to tell someone who's saying "do this", "no."

To answer your question directly:

"why we cannot create an object for an abstract class?"

Hopefully you see now, abstract classes only define the functionality the concrete class should be able to do. The abstract class itself is only a blue-print; you don't live in blue-prints, you live in houses that implement the blue-prints.

like image 150
GManNickG Avatar answered Oct 16 '22 08:10

GManNickG


The problem is simply this:

  • what should the program do when an abstract method is called?
  • and even worse: what should be returned for a non-void function?

The application whould proabably have to crash or thow a runtime exception and thus this would cause trouble. You can't dummy-implement every abstract function.

like image 45
abenthy Avatar answered Oct 16 '22 07:10

abenthy


A class can simply be declared abstract where it has no abstract methods. I guess that could be instantiated in theory but the class designer doesn't want you to. It may have unintended consequences.

Usually however abstract classes have abstract methods. They can't be instantiated for the simple reason that they're missing those methods.

like image 3
cletus Avatar answered Oct 16 '22 08:10

cletus


Because logically it does not make any sense.

An abstract class is a description that is incomplete.
It indicates what things need to be filled out to make it complete but without those bits its not complete.

My first example was a chess game:
The game has lots of pieces of different type (King,Queen,Pawn ... etc).

But there are no actual objects of type piece, but all objects are instances of objects derived from piece. How can you have an object of something that is not fully defined. There is not point in creating an object of piece as the game does not know how it moves (that is the abstract part). It knows it can move but not how it does it.

like image 3
Martin York Avatar answered Oct 16 '22 06:10

Martin York