The purpose of an abstract class is to define a common protocol for a set of concrete subclasses. This is useful when defining objects that share code, abstract ideas, etc.
Abstract classes have no instances. An abstract class must have at least one deferred method (or function). To accomplish this in C++, a pure virtual member function is declared but not defined in the abstract class:
class MyClass {
virtual void pureVirtualFunction() = 0;
}
Attempts to instantiate an abstract class will always result in a compiler error.
"What does defining an abstract base class provide that isn't provided by creating each necessary function in each actual class?"
The main idea here is code reuse and proper partitioning across classes. It makes more sense to define a function once in a parent class rather than defining over and over again in multiple subclasses:
class A {
void func1();
virtual void func2() = 0;
}
class B : public A {
// inherits A's func1()
virtual void func2(); // Function defined in implementation file
}
class C : public A {
// inherits A's func1()
virtual void func2(); // Function defined in implementation file
}
Answer from Chris Dargis on Stack OverflowVideos
The purpose of an abstract class is to define a common protocol for a set of concrete subclasses. This is useful when defining objects that share code, abstract ideas, etc.
Abstract classes have no instances. An abstract class must have at least one deferred method (or function). To accomplish this in C++, a pure virtual member function is declared but not defined in the abstract class:
class MyClass {
virtual void pureVirtualFunction() = 0;
}
Attempts to instantiate an abstract class will always result in a compiler error.
"What does defining an abstract base class provide that isn't provided by creating each necessary function in each actual class?"
The main idea here is code reuse and proper partitioning across classes. It makes more sense to define a function once in a parent class rather than defining over and over again in multiple subclasses:
class A {
void func1();
virtual void func2() = 0;
}
class B : public A {
// inherits A's func1()
virtual void func2(); // Function defined in implementation file
}
class C : public A {
// inherits A's func1()
virtual void func2(); // Function defined in implementation file
}
Having an abstract class like "Dog" with a virtual method like "bark" allows all classes that inherit from Dog to have their bark code called in the same way, even though the Beagle's bark is implemented way differently than the Collie's.
Without a common abstract parent (or at least a common parent with a bark virtual method) it'd be difficult to do the following:
Have a Vector of type Dog that contains Collies, Beagles, German Shepherds etc and make each of them bark. With a Vector of Dogs that contains Collies, Beagles, German Shepherds all you would have to do to make them all bark is to iterate through in a for loop and call bark on each one. Otherwise you'd have to have a separate Vector of Collies, Vector of Beagles etc.
If the question is "why make Dog abstract when it could be concrete, have a virtual bark defined with a default implementation that can be overriden?", the answer would be that this may be acceptable sometimes -- but, from a design perspective, there really isn't any such thing as a Dog that isn't a Collie or a Beagle or some other breed or mix so although they are all Dogs, there is not one of them in reality that is a Dog but not some other derived class too. Also, since dogs barking is so varied from one breed to another, there is unlikely to be any real acceptable default implementation of bark that would be acceptable for any decent group of Dogs.
I hope this helps you understand the purpose: yes, you're going to have to implement bark in each subclass anyway, but the common abstract ancestor lets you treat any subclass as a member of a base class and invoke behaviors that may be conceptually similar like bark but in fact have very different implementations.
Typically, Objective-C class are abstract by convention only—if the author documents a class as abstract, just don't use it without subclassing it. There is no compile-time enforcement that prevents instantiation of an abstract class, however. In fact, there is nothing to stop a user from providing implementations of abstract methods via a category (i.e. at runtime). You can force a user to at least override certain methods by raising an exception in those methods implementation in your abstract class:
[NSException raise:NSInternalInconsistencyException
format:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)];
If your method returns a value, it's a bit easier to use
@throw [NSException exceptionWithName:NSInternalInconsistencyException
reason:[NSString stringWithFormat:@"You must override %@ in a subclass", NSStringFromSelector(_cmd)]
userInfo:nil];
as then you don't need to add a return statement from the method.
If the abstract class is really an interface (i.e. has no concrete method implementations), using an Objective-C protocol is the more appropriate option.
No, there is no way to create an abstract class in Objective-C.
You can mock an abstract class - by making the methods/ selectors call doesNotRecognizeSelector: and therefore raise an exception making the class unusable.
For example:
- (id)someMethod:(SomeObject*)blah
{
[self doesNotRecognizeSelector:_cmd];
return nil;
}
You can also do this for init.
In most cases, your abstract class contains abstract ("pure virtual" in C++ terms) methods:
class Foo {
public:
virtual ~Foo() = default;
virtual void bar() = 0;
};
That is sufficient to make it an abstract class:
Foo foo; // gcc says: cannot declare variable 'foo' to be of abstract type 'Foo'
Note that you really want to declare the destructor as virtual in your base class, or you risk undefined behavior when destroying your derived object through a base class pointer.
There also might be cases when you have no abstract methods, but still want to mark your class as abstract. There are two ways:
a. Declare your base destructor as pure virtual:
class Foo {
public:
virtual ~Foo() = 0;
virtual void bar() { }
};
Foo::~Foo() = default; // need to define or linker error occurs
b. Declare all your base constructors as protected:
class Foo {
public:
virtual ~Foo() = default;
virtual void bar() { }
protected:
Foo() = default;
};
My question is can I abstract test class like this?
No, you can't. An abstract class by definition is a class that contains at least one pure virtual function.
I understand what an abstract class is and how it works, but I don't get the point.
My thinking is: If you are going to create undefined methods in the abstract class, only to define them in each sub-class, why create the abstract in the first place.
What is it that I'm missing?
You should distinguish between a language construct as abstract classes and a generic concept as abstraction.
Although abstract classes may be a useful tool in creating abstractions it's not a necessary tool, neither is using that tool a guarantee that you would get a (good) abstraction.
For example there are abstractions all over the place in the C++ standard so one should not require to come up with another example.
Take for example the STL. There are a number of containers of different kind, but for example there are sequences which all conform to a common set of functions defined on them, in addition there are guaranteed complexities for different operations depending on which one you select. The abstraction here is that these are sequential containers that you can use to store data in. Although they don't use virtual functions, the implementation varies from implementation to implementation (or at least could vary), but if you use it according to the specification the actual implementation would not matter to the programmer (and most often the programmer does not dig into the actual implementation).
Another abstraction in the specification is the language itself, the execution environment specified therein and the translation process. These parts are not specified in terms of how they are implemented, but according to the expected behavior. For example normally an implementation would implement local variables by putting them on the processor stack, but that is an implementation detail that the C++ specification leaves out. The specification puts up a number of assumptions about the behavior of the execution. And you construct your program using these assumptions instead of assuming that the implementation would need to be done in a specific concrete way.
Abstraction is something very natural in every day life, it is very common to talk about something without getting into many details of the thing. You can use your car without thinking/knowing about mechanics, fluid mechanics, chemistry, engineering, etc. Abstraction in computer engineering is exactly the same thing (in general).
Yes a simple function provides an abstraction. But functions are just small parts of a software, and they are sometimes built by factoring the code (a good idea but that do not always lead to a good abstraction). An abstraction should have a clear semantic meaning not tricky.
OOP is a paradigm in witch you can built new types and let you forget about the details of them. As in an course about algorithm where one can tell you how quicksort works but never speak about the real nature of the elements they are sorting (it is certainly not an interesting point in sorting). What is interesting about object (as with your car) is the way one can manipulate an object not how the behavior is realized. I want to turn to the left by rotating the steering to the left, I don't want to know that really happens behind the scene when I do this. When I leave my car to the repair man, I let him do anything he wants on my car provided that it works as usual (he can change anything he wants behind the scene). As a user I just want to focus on the manual not the internals. So you need to make a difference in between the interface of an ideal object (the manual) and the realization of a concrete object (the internals schemas). This is what every OOP language let you write (in different ways of course you have a variety of possibilities to realize all of this).
So you want to talk about points on the plane somewhere in your code? Let's talk about the manual (a short one for the sake on simplicity). A Point is an object from which you can get its cartesian coordinates or its polar ones, right? Then its abstract, whatever a Point is obtain/realized in the software you want to be able to do this with it. So it is an abstraction:
class Point {
public:
virtual double getX() = 0;
virtual double getY() = 0;
virtual double getAngle() = 0;
virtual double getLength() = 0;
}
This is a manual, with this you can use a point (provided you have one), then you can write a valid compilable code:
void f(Point *p) {
cout << p->getX() << "," << p->getY() << endl;
}
Here you need to be careful, either pass a pointer or a reference. You pass an object as an abstraction, then something should happen to retrieve the realization, in C++ this necessitate reference or pointer. Note that this function does not receive a Point (a Point is an abstraction something that doesn't exists), but can receive any kind of realization of a Point (this makes a big difference). Note: that this code is compilable and remains valid while you call it with a realization of the abstraction (this can be valid for a very very long time! Code reusability, you know?)
Ok now somewhere you can realize the abstraction:
class PolarPoint : public Point {
private:
double angle, length;
public:
PolarPoint(double a,double l) : angle(a), length(l) {}
virtual double getX() { return length*cos(angle); }
virtual double getY() { return length*sin(angle); }
virtual double getLength() { return length; }
virtual double getAngle() { return angle; }
}
Somewhere you instantiate it (create an object of this concrete model and then use it (then forget about all of its specificity) :
...
Point *p = new PolarPoint(3.14/4,10.0);
f( p );
....
Remind that f has been compiled even a long time ago, but works with this new realization now! An abstraction is a kind of contract.
You can also realize in another way:
class CartesianPoint : public Point {
private:
double x, y;
public:
CartesianPoint(double x,double y) : x(x), y(y) {}
virtual double getX() { return x; }
virtual double getY() { return y; }
virtual double getLength() { return /* the calculus from x/y*/; }
virtual double getAngle() { return /* the calculus from x/y */; }
}
...
Point *p2 = new CartesianPoint(3.14/6,20.56);
f( p );
...
In this example I also used information hiding, concept related to abstraction (at least useful with abstraction). private/public is related to information hiding, which lets you enforce the hiding, meaning that the user of a class can't access (at least too easily) the details, not only he is discouraged from look at them but he can't manipulate them. Again, with your car, it is not easy to change a piston, not only because it is an inner part of the engine but also because the constructor provide many ways to hide this from you : no instruction manual to do so, special tools difficult to obtain, etc. You may know that your car has a carburetor, but you may be unable to touch it.
Beware that abstraction does not mean hiding, but just let you forget about the details if you don't want to (and in general you don't want to). Abstraction is a good way to obtain low coupling of software components.