views:

538

answers:

7

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

+1  A: 

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.

cletus
Yes, what "unintended consequences" are possible? Suppose I guarantee that my object will never call any of its functions?
Amoeba
By declaring a method a class has made a contract tos ay that you can call that method. The class contract will describe what that function does, what arguments it takes and what it returns (if anything). An abstract class wouldn't be able to fulfill that contract.
cletus
If you make a method `abstract` you expect it *must* be implemented by its subclass, and want the compiler to catch errors for you when that method is called not via a subclass. If you don't require that method to be called, simply leave it out or supply a default implementation.
KennyTM
@cletus Yes, I totally understand that. Suppose I decide to redesign C++ so that I can create objects for abstract classes. Is it possible to do that?
Amoeba
@cambr: What's the point of being abstract then? ;)
KennyTM
@KennyTM for a moment, just forget the logic. What I want to know is whether it is possible at all?
Amoeba
Anything is possible if you make up the rules.
GMan
@cambr: No (for C++).
KennyTM
@KennyTM do you have a reason WHY?
Amoeba
@GMan thats what I want to know: if I "make up the rules", is it possible?
Amoeba
@cambr: C++ is a statically (and strongly) typed language. Of course you could design a language that works different. For example, Javascript is loosely and dynamically typed and it has first class functions so you can at runtime add methods to a class or to a particular object (or take them away even). As a result Javascript has no abstract classes because the concept doesn't make sense in that context. It does in C++ however.
cletus
@cambr: I've explained a few comments above.
KennyTM
+1  A: 

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.

Martin York
+4  A: 

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.

abenthy
A: 

Abstract classes instantiated would be pretty useless, because you would be seeing a lot more of "pure virtual function called". :)

It's like: we all know that a car would have 3 pedals and a steering wheel and a gear stick. Now, if that would be it, and there'd be an instance of 3 pedals and gear stick and a wheel, I'm not buying it, I want a car, like with seats, doors, AC etc. with pedals actually doing something apart from being in existence and that's what abstract class doesn't promise me, the ones implementing it do.

Dmitry
+7  A: 

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.

GMan
@Gman: thanks for all the details
Amoeba
A: 

Abstract classes are non-instantiable by definition. They require that there be derived, concrete classes. What else would an abstract class be if it didn't have pure virtual (unimplemented) functions?

jamesdlin
A: 

It's the same class of question as why can't I change the value of a const variable, why can't I access private class members from other classes or why can't I override final methods.

Because that's the purpose of these keywords, to prevent you from doing so. Because the author of the code deemed doing so dangerous, undesired or simply impossible due to some abstract reasons like lack of essential functions that need to be added by specific child classes. It isn't really that you can't instantiate because a class is virtual. It's that inability to instantiate a class defines it as virtual (and if a class that can't be instantiated isn't virtual, it's an error. Same goes the other way, if instance of given class makes sense, it shouldn't be marked as virtual)

SF.