C++ Abstract Class Without Pure Virtual Functions

C++ abstract class without pure virtual functions?

You could declare, and implement, a pure virtual destructor:

class ShapeF
{
public:
virtual ~ShapeF() = 0;
...
};

ShapeF::~ShapeF() {}

It's a tiny step from what you already have, and will prevent ShapeF from being instantiated directly. The derived classes won't need to change.

Can an abstract class be implemented without pure virtual functions in C++?

It is unclear what you are really asking for. So let me try to clear some points:

Pure virtual functions can have definitions

If your concern is that you want to provide definitions for all of the virtual functions in your base you can provide the definitions for the pure virtual functions, and they will be available for static dispatch.

Protected grants access to your base subobject, not to every instance of base

There is a common misconception that protected allows a particular derived type accessing any instance of base. That is not true. The keyword protected grants access to the base subobject within the derived type.

class base {
protected: base() {}
};
class derived : public base {
derived() : base() { // fine our subobject
base b; // error, `b` is not your subobject
}
};

Making a class abstract without any pure virtual methods

You can declare a pure virtual destructor, but give it a definition. The class will be abstract, but any inheriting classes will not by default be abstract.

struct Abstract
{
virtual ~Abstract() = 0;
};

Abstract::~Abstract() {}

struct Valid: public Abstract
{
// Notice you don't need to actually overide the base
// classes pure virtual method as it has a default
};

int main()
{
// Abstract a; // This line fails to compile as Abstract is abstract
Valid v; // This compiles fine.
}

Can a C++ class without any pure virtual methods be considered abstract?

abstract classes must have one or more pure virtual methods.

Exactly, and you class don't have it.

In accordance with this, a abstract class is a type which cannot be instantiated, but can be used as a base class (note: not "by"). In C++ this can be achieved with the usage of pure virtual method.

A pure virtual method is a virtual function whose declarator has the following syntax:

class B {
virtual void foo() = 0;
}

Note: the syntax = 0 which indicates a pure virtual method. That simply means you don't have to specify an implementation for that method, and it cannot be possible to create any instance of that class (that is, a abstract class).

In conclusion your class B is not an abstract class.

Finally, is the term abstract class defined in any of the recent C++ standards?

The abstract class is a definition itself, and it's define as I've just mentioned before.

If you mean a specific defined syntax as, for example in Java (abstract class ...), then the answer is no. Again an abstract class in C++ is defined just with a class which has a pure virtual method.

C++: How to create an abstract base class if class has no member functions?

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]

Defining interfaces (abstract classes without members) in C++

You ask a lot of questions, but I'll give it a shot.

By an interface (C# terminology) I mean an abstract class with no data members.

Nothing specifically like a C# interface exists. A C++ abstract base class comes the closest, but there are differences (for example, you will need to define a body for the virtual destructor).

Thus, such a class only specifies a contract (a set of methods) that sub-classes must implement. My question is: How to implement such a class correctly in modern C++?

As a virtual base class.

Example:

class OutputSink
{
public:

~OutputSink() = 0;

// contract:
virtual void put(std::vector<std::byte> const& bytes) = 0;
};

OutputSink::~OutputSink() = default;

Hence I guess it should be declared with the struct keyword, since it only contains public members anyway.

There are multiple conventions for when to use a structure versus a class. The guideline I recommend (hey, you asked for opinions :D) is to use structures when you have no invariants on their data. For a base class, please use the class keyword.

"A polymorphic class should suppress copying"

Mostly true. I have written code where the client code didn't perform copies of the inherited classes, and the code worked just fine (without prohibiting them). The base classes didn't forbid it explicitly, but that was code I was writing in my own hobby project. When working in a team, it is good practice to specifically restrict copying.

As a rule, don't bother with cloning, until you find an actual use case for it in your code. Then, implement cloning with the following signature (example for my class above):

virtual std::unique_ptr<OutputSink> OutputSink::clone() = 0;

If this doesn't work for some reason, use another signature (return a shared_ptr for example). owner<T> is a useful abstraction, but that should be used only in corner cases (when you have a code base that imposes on you the use of raw pointers).

An interface should consist only of public methods. It should declare [...]. It should [...]. It should be derived using public virtual.

Don't try to represent the perfect C# interface in C++. C++ is more flexible than that, and rarely will you need to add a 1-to-1 implementation of a C# concept in C++.

For example, in base classes in C++ I sometimes add public non-virtual function implementations, with virtual implementations:

class OutputSink
{
public:
void put(const ObjWithHeaderAndData& o) // non-virtual
{
put(o.header());
put(o.data());
}

protected:
virtual void put(ObjectHeader const& h) = 0; // specialize in implementations
virtual void put(ObjectData const& d) = 0; // specialize in implementations
};

thus the abstract base-class always needs to declare a default constructor?! Am I misunderstanding something?

Define the rule of 5 as needed. If code doesn't compile because you are missing a default constructor, then add a default constructor (use the guidelines only when they make sense).

Edit: (addressing comment)

as soon as you declare a virtual destructor, you have to declare some constructor for the class to be usable in any way

Not necessarily. It is better (but actually "better" depends on what you agree with your team) to understand the defaults the compiler adds for you and only add construction code when it differs from that. For example, in modern C++ you can initialize members inline, often removing the need for a default constructor completely.

abstract class and virtual functions

Would this class be considered an abstract class because it has one virtual function? I was still able to create an Animal object and call getFoodCost();

No. In C++, "Abstract Class" usually refers to a class with a pure virtual function:

class Abstract {
public:
virtual void PureVirtual() = 0; // no implementation
};

class NotAbstract {
virtual void NotPureVirutal() {
// Some implementation
}
};

I thought abstract classes cannot be instantiated.

Yes, that is correct. This is because abstract classes have functions with no required implementation. It has no way to instantiate an instance directly. It uses inheritance and pointers/references to refer to an abstract class.

Does this mean objects can have virtual functions and not be considered abstract class?

Yes. Again, abstract classes are classes that have pure virtual functions. This is different from a regular virtual function. As discussed above, pure virtual functions have no required implementation. Regular virtual functions, on the other hand, are required to have an implementation associated with them, so they can be instantiated.

c++ abstract classes using pure virtual functions in non pure virtual functions

Why don't you simply add it to the constructor of the every child class?

If you want to avoid writing it every time in the constructor (or even skipping or inheriting it) then you could use CRTP:

class Parent {
public:
Parent(){};
virtual void helloWorld() = 0; // no standard hello...
};

template <typename Par>
class ParentCRTP: public Parent {
public:
ParentCRTP(){
Par::doHelloWorld();
};
virtual void helloWorld(){
Par::doHelloWorld();
}
};

class Child : public ParentCRTP<Child> {
public:
static void doHelloWorld(){ // childs implementation of helloWorld
std::cout << "Hello, World!\n";
};
};

This approach will not give you a pointer to the child class in your child's hello method - at this point class instance is only Parent instance, no valid Child pointer can be obtained. To force an execution of Child's method after construction you can only use two stage initialization: First you create class instance using a constructor, and then initialize it using separate method.

Apart from that, problem like this is probably a hint to re-think your design. You shouldn't force your classes to initialize itself in a given way.



Related Topics



Leave a reply



Submit