Implementation of abstract classes

R

Rune Allnor

Hi folks.

I have some classes which are derived from some base:

class base {
void foo();
void bar();
};

class a : public base {
};

class b: public base{
};

The problem is as follows:

1) I would like to prevent users from making instances of
class base
2) There are no overloaded functions beween the base class
and the derived classes, so I can not use the usual

virtual void overloaded_function() = 0;

in the base class.

As far as I can see, there are two ways to proceed:

1) make some virtual dummy function that the
derived classes need to implement
2) Hide the constructor of base as protected.

From a semantic point of view the latter solution
seems the more elegant. Is this a good solution
or are there traps or snags associated with it?

Rune
 
R

Rune Allnor

If your base class is going to be used polymorphically, you must declare
its destructor virtual anyway, so you don't need a "dummy" pure virtual
function. Just declare the destructor itself pure virtual:

virtual ~base() = 0

Of course!

This solution takes care of the case I'm working on
right now, but how would one do this if there were
some cleaning up to do on the base class level?

With the above solution one would have to call some
base::cleanup() function in each of the derived
destructors, right?

Rune
 
E

Erik Wikström

Of course!

This solution takes care of the case I'm working on
right now, but how would one do this if there were
some cleaning up to do on the base class level?

With the above solution one would have to call some
base::cleanup() function in each of the derived
destructors, right?

Just because a function is pure virtual does not mean it cannot be
implemented:

#include <iostream>

struct Base
{
virtual ~Base() = 0
{
std::cout << "~Base\n";
}
};

struct Derived : public Base
{
~Derived()
{
std::cout << "~D\n";
}
};

int main() {
Derived d;
return 0;
}
 
T

terminator

Just because a function is pure virtual does not mean it cannot be
implemented:

#include <iostream>

struct Base
{
  virtual ~Base() = 0
  {
    std::cout << "~Base\n";
  }

verrry interesting!!!!!!!!!!!!!!!!!!!
are you sure???????????????????????

regards,
FM.
 
J

James Kanze

I have some classes which are derived from some base:
class base {
void foo();
void bar();
};
class a : public base {
};
class b: public base{
};
The problem is as follows:
1) I would like to prevent users from making instances of
class base
2) There are no overloaded functions beween the base class
and the derived classes, so I can not use the usual
virtual void overloaded_function() = 0;
in the base class.
As far as I can see, there are two ways to proceed:
1) make some virtual dummy function that the
derived classes need to implement
2) Hide the constructor of base as protected.
From a semantic point of view the latter solution
seems the more elegant. Is this a good solution
or are there traps or snags associated with it?

I don't know about elegance, but the second solution is
certainly the usual solution.
 
R

Rune Allnor

Just because a function is pure virtual does not mean it cannot be
implemented:

#include <iostream>

struct Base
{
  virtual ~Base() = 0
  {
    std::cout << "~Base\n";
  }
};

Can this be correct? The way I understand

virtual void foo() = 0;

is that the statement inituializes a NULL
pointer in the virtaul function table.
It this is correct your code above will
result in undefined behaviour.

Rune
 
E

Erik Wikström

Can this be correct? The way I understand

virtual void foo() = 0;

is that the statement inituializes a NULL
pointer in the virtaul function table.
It this is correct your code above will
result in undefined behaviour.

Actually it is *not* a correct solution to Rune's problem, but not
because the reason you mentioned. The C++ standard does not mention
vtables or such things, it only defines what is supposed to happen and
leaves to the compiler to use the best technique to make it happen.

The "= 0" at the end of a function declaration means that the function
is pure virtual, and a class with a pure virtual function is abstract
(it can not be instantiated). This means that any derived classes have
to either implement the function or they will abstract too.

The reasons my code was not correct is that the standard does not allow
a pure function to be defined together with the declaration:

struct Foo
{
virtual void bar() = 0 { 1+1; } // Error
};

You can, however, provide the the definition separately:

struct Foo
{
virtual void bar() = 0;
};

void Foo::bar()
{
1 + 1;
}

You can also call a pure virtual function using a qualified expression:

struct Foo
{
virtual void bar() = 0;
};

void Foo::bar()
{
std::cout << "Foo::bar()\n";
}

struct Baz : public Foo
{
void bar()
{
std::cout << "Baz::bar()\n"
Foo::bar();
}
};

int main()
{
Foo* f = new Baz();
f->bar();
return 0;
}

Output:
Baz::bar()
Foo::bar()
 
J

James Kanze

Can this be correct? The way I understand
virtual void foo() = 0;
is that the statement inituializes a NULL pointer in the
virtaul function table.

It might. All the standard says is that if a virtual function
call resolves to a pure virtual function, the behavior is
undefined.
It this is correct your code above will result in undefined
behaviour.

Only if you manage to have a virtual function call resolve to
Base::~Base. And I don't see any way of doing that that
wouldn't create undefined behavior anyway. (Basically, the only
way you could have it would be with an explicit destructor call
from a constructor or the destructor of Base.)
 
J

Juha Nieminen

Rune said:
Can this be correct? The way I understand

virtual void foo() = 0;

is that the statement inituializes a NULL
pointer in the virtaul function table.

You understand wrongly. The "=0" part is nothing more than a way of
saying "pure". (The story goes that Stroustrup wanted to use the keyword
"pure", but the standardization committee didn't want any more
single-use keywords, so Stroustrup came up with the next best thing he
could come up with, which was adding "=0" to the method declaration.)

A pure virtual function is in all ways a regular virtual function,
with the exception that it *must* be implemented in a derived class, and
if there's a pure virtual function in the base class, that base class
cannot be instantiated all by itself. The difference between a virtual
function and a pure virtual function is purely semantical.

This means that a pure virtual function can have an implementation in
the exact same way as a regular virtual function can. You can call this
implementation by calling it explicitly, eg. Base::foo();

In the case of a pure virtual destructor, the destructor of the base
class is called automatically (so it doesn't need to be called explicitly).
 
J

James Kanze

[...]
(The story goes that Stroustrup wanted to use the keyword
"pure", but the standardization committee didn't want any more
single-use keywords, so Stroustrup came up with the next best
thing he could come up with, which was adding "=0" to the
method declaration.)

I too have heard that there was a desire not to introduce new
keywords at that time, but you can't blame the committee: pure
virtual functions were present before the committee was founded.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top