Provide a pure virtual destructor:
struct Base {
virtual ~Base() = 0;
};
inline Base::~Base() {}
You need to provide an implementation, which you could right in the header by making it inline.
An abstract class is a class with some pure virtual function:
[...] A class is abstract if it has at least one pure virtual function. [...]
[N4431 §10.4/2]
Since you want an array of pointers to instances of (classes derived from) your abstract class, I assume you also want to be able to eventually delete and thus destruct one or more of those instances via these pointers:
Base * instance = // ... whatever ...
delete instance;
To call the correct destructor (of the derived class) in that case, the destructor has to be virtual.
So since it's virtual either way, and you don't want some pure virtual member function, it's best to make the destructor pure virtual.
To make a virtual function pure, you append the pure-specifier to its declaration:
struct Foo {
virtual void bar(void) /* the */ = 0; // pure-specifier
};
Now, regarding the definition, you wonder why we need to provide one, since ...
[...] A pure virtual function need be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1). [...]
[N4431 §10.4/2]
This is because when destructing a derived class, after the derived classes destructor has been called, the destructors of the bases classes will also be called:
struct Derived : public Base {
~Derived() {
// contents
// Base::~Base() will be called
}
};
After executing the body of the destructor [...] a destructor for class X calls [...] the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name [...]
[N4431 §12.4/8]
So a definition of the pure virtual destructor if the Base class is needed. However ...
[...] A function declaration cannot provide both a pure-specifier and a definition [...]
[N4431 §10.4/2]
... so it has to be defined outside of the class definition. This could be done in a separate source file, or thanks to ...
An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case [...]
[N4431 §7.1.2/4]
... as a inline function in the header.
The standard is even explicit about the requirement of a definition in this case:
Answer from Daniel Jour on Stack OverflowA destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. [...]
[N4431 §12.4/9]
C++: How to create an abstract base class if class has no member functions? - Stack Overflow
Declare abstract class in c++ - Stack Overflow
Good practice to design a ABC(Abstract Base Class) in C++ - Stack Overflow
c++ abstract base class private members - Stack Overflow
Videos
Provide a pure virtual destructor:
struct Base {
virtual ~Base() = 0;
};
inline Base::~Base() {}
You need to provide an implementation, which you could right in the header by making it inline.
An abstract class is a class with some pure virtual function:
[...] A class is abstract if it has at least one pure virtual function. [...]
[N4431 §10.4/2]
Since you want an array of pointers to instances of (classes derived from) your abstract class, I assume you also want to be able to eventually delete and thus destruct one or more of those instances via these pointers:
Base * instance = // ... whatever ...
delete instance;
To call the correct destructor (of the derived class) in that case, the destructor has to be virtual.
So since it's virtual either way, and you don't want some pure virtual member function, it's best to make the destructor pure virtual.
To make a virtual function pure, you append the pure-specifier to its declaration:
struct Foo {
virtual void bar(void) /* the */ = 0; // pure-specifier
};
Now, regarding the definition, you wonder why we need to provide one, since ...
[...] A pure virtual function need be defined only if called with, or as if with (12.4), the qualified-id syntax (5.1). [...]
[N4431 §10.4/2]
This is because when destructing a derived class, after the derived classes destructor has been called, the destructors of the bases classes will also be called:
struct Derived : public Base {
~Derived() {
// contents
// Base::~Base() will be called
}
};
After executing the body of the destructor [...] a destructor for class X calls [...] the destructors for X’s direct base classes and, if X is the type of the most derived class (12.6.2), its destructor calls the destructors for X’s virtual base classes. All destructors are called as if they were referenced with a qualified name [...]
[N4431 §12.4/8]
So a definition of the pure virtual destructor if the Base class is needed. However ...
[...] A function declaration cannot provide both a pure-specifier and a definition [...]
[N4431 §10.4/2]
... so it has to be defined outside of the class definition. This could be done in a separate source file, or thanks to ...
An inline function shall be defined in every translation unit in which it is odr-used and shall have exactly the same definition in every case [...]
[N4431 §7.1.2/4]
... as a inline function in the header.
The standard is even explicit about the requirement of a definition in this case:
A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined. [...]
[N4431 §12.4/9]
Is it possible to create a memberless abstract base class?
The simplest way is to make the destructor pure virtual.
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
};
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.
- Do not provide an implementation for pure virtual methods unless it is necessary.
- Do not make your destructor pure virtual.
- Do not make your constructor protected. You cannot create an instance of an abstract class.
- Better hide an implementation of constructor and destructor inside a source file not to pollute other object files.
- Make your interface non-copyable.
If this is an interface, better do not have any variables there. Otherwise it would be an abstract base class and not an interface.
Too many pure functions is OK unless you can do it with less pure functions.
In C++, generally speaking, we should avoid the usage of multiple inheritance
Like any other language feature, you should use multiple inheritance wherever it is appropriate. Interfaces are generally considered an appropriate use of multiple inheritance (see, for example, COM).
The constructor of ABC needs not be protected--it cannot be constructed directly because it is abstract.
The ABC destructor should not be declared as pure virtual (it should be declared as virtual, of course). You should not require derived classes to implement a user-declared constructor if they do not need one.
An interface should not have any state, and thus should not have any member variables, because an interface only defines how something is to be used, not how it is to be implemented.
ABC should never have too many member functions; it should have exactly the number that are required. If there are too many, you should obviously remove the ones that are not used or not needed, or refactor the interface into several more specific interfaces.
In C++ you can have an abstract class that has non pure virtual methods. In that case, and depending on the design it can make sense to have private members:
class base {
std::string name;
public:
base( std::string const & n ) : name(n) {}
std::string const & getName() const { return name; }
virtual void foo() = 0;
};
That code ensures that every object that derives from base has a name, that is set during construction and never changes during the lifetime of the object.
EDIT: For completion after Charles Bailey reminded me of it in his answer
You can also define pure-virtual functions, and in that case, private attributes could also make sense:
// with the above definition of base
void base::foo() {
std::cout << "My name is " << name << std::endl;
}
It's normally not advisable to have data members in an abstract class but there is nothing technically wrong with your example. In the implementation of foo, which is publicly accessible you can use myInt for whatever purposes you like.
For example:
class abc{
public:
virtual void foo()=0;
private:
int myInt;
};
class xyz : public abc
{
virtual void foo();
};
#include <iostream>
#include <ostream>
void xyz::foo()
{
std::cout << "xyz::foo()\n";
abc::foo();
}
void abc::foo()
{
std::cout << "abc::foo(): " << myInt++ << '\n';
}
#include <memory>
int main()
{
std::auto_ptr<abc> p( new xyz() ); // value-initialization important
p->foo();
p->foo();
}
Output:
xyz::foo()
abc::foo(): 0
xyz::foo()
abc::foo(): 1
I'm having trouble understanding ABC's in c++ and was wondering if you all could help me (if possible use: CryptProcessor as the ABC and ACrpyt and BCrypt as the sub-classes that have an encrypt and decrypt function) Thanks in advance!
Edit 1: Thank you all for your help!