Base struct instead of class

  • Thread starter Marcin Vorbrodt
  • Start date
M

Marcin Vorbrodt

Taken out of C++ In a Nutshell book...

Example 7-18: Using an abstract classes as interface specification.
struct Runnable {
virtual void run() = 0;
};

struct Hashable {
virtual size_t hash() = 0;
};

class Thread : public Runnable, public Hashable {
public:
Thread() { start_thread(*this); }
Thread(const Runnable& thread) { start_thread(thread); }
virtual void run();
virtual size_t hash() const { return thread_id(); }
size_t thread_id() const;
...
private:
static void start_thread(const Runnable&);
};

What would the advantage be of using struct as an interface (pure virtual
base class)?
Thanks,Martin
 
T

Thomas J. Clancy

brevity. Thus you don't have to type:

class Runnable
{
public:
virtual void run() = 0;
};

Otherwise there is no advantage. Personally I use struct only when I want
to group variables so that I might write it as a block of bytes to a file or
read from a file. Otherwise I use class if the intention is to contain
functionality (e.g. methods).

Tom
 
T

Thomas J. Clancy

Kevin Goodsell said:
<snip>

Please don't top-post. Re-read section 5 of the FAQ for posting
guidelines. You could also find this rule in pretty much any netiquette
reference, including RFC 1855.

http://www.parashift.com/c++-faq-lite/

-Kevin

Ah yes, I'd forgotten about this particular quirk of posting in most
newsgroups. I find non-top posting appalling unless I am addressing
specific pieces of the posted question or questions. But alas, I am in the
minority. Still, I find it logical that should someone ask one simple
question, rather than have to scan down to find the answer, if it is at the
top he/she can immediately see the answer--thus instant gratification.

Anyway, since it seems to anger you and perhaps others I will, to my own
dismay, comply.

T. Clancy
 
A

Alf P. Steinbach

Ah yes, I'd forgotten about this particular quirk of posting in most
newsgroups. I find non-top posting appalling unless I am addressing
specific pieces of the posted question or questions. But alas, I am in the
minority. Still, I find it logical that should someone ask one simple
question, rather than have to scan down to find the answer, if it is at the
top he/she can immediately see the answer--thus instant gratification.

That assumes (1) someone has followed the whole thread down to the answer
(which is much work), and (2) a tool that displays the text positioned at
the top by default, and (3) something more complicated than Ctrl-End or
Page Down to move down in the text; I doubt whether all that can be true
very often.

Anyway, since it seems to anger you and perhaps others I will, to my own
dismay, comply.

Thanks, and please pass the word (it's September again).
 
I

Ivan Vecerina

Marcin Vorbrodt said:
Taken out of C++ In a Nutshell book...

Example 7-18: Using an abstract classes as interface specification.
struct Runnable {
virtual void run() = 0;
};

struct Hashable {
virtual size_t hash() = 0;
};

As Thomas mentioned, this only saves you from having to add
a 'public:' specification. Except for the public access
specifications, all uses of keyword 'struct' can be relaced
by 'class' in C++.
Using struct is a matter of style choice. struct is commonly
used for structs that have no methods or invariants, and
have only public data members.
The author of your book chose to apply it to interfaces too.

One comment though: IMO interface classes such as the ones
above should have a protected destructor (if not a virtual
destructor):
class Runnable {
public:
virtual void run() = 0;
protected:
~Runnable() {}
};
If you don't intend users of the interface to delete
instances by using a pointer to this interface, it should
be made explicit -- a protected destructor does it.
If it is acceptable to do so, the destructor shall
be virtual.

See also: http://www.gotw.ca/publications/mill18.htm
"Guideline #4: A base class destructor should be either public and virtual,
or protected and nonvirtual."


I hope you'll find this useful...
 
W

White Wolf

Marcin said:
Taken out of C++ In a Nutshell book...

Example 7-18: Using an abstract classes as interface specification.
struct Runnable {
virtual void run() = 0;
};

struct Hashable {
virtual size_t hash() = 0;
};

class Thread : public Runnable, public Hashable {
public:
Thread() { start_thread(*this); }
Thread(const Runnable& thread) { start_thread(thread); }
virtual void run();
virtual size_t hash() const { return thread_id(); }
size_t thread_id() const;
...
private:
static void start_thread(const Runnable&);
};

What would the advantage be of using struct as an interface (pure
virtual base class)?


First: *all* of your classes *must* have a virtual destructor. They all
have virtual functions. Especially hashable and runnable *must* have
virtual destructors.

Second: the advantage is less typing. You do not need to say "public:"
 
K

Kevin Goodsell

Thomas said:
Ah yes, I'd forgotten about this particular quirk of posting in most
newsgroups.

It applies to all one-to-many communications on the net, not just
newsgroups. See RFC 1855. It's also not a "quirk", it is a standard.
I find non-top posting appalling unless I am addressing
specific pieces of the posted question or questions. But alas, I am in the
minority. Still, I find it logical that should someone ask one simple
question, rather than have to scan down to find the answer, if it is at the
top he/she can immediately see the answer--thus instant gratification.

But then everyone else has to scan down to see what the question was. Is
your time more valuable than that of the hundreds of others reading the
group?

Top-posting creates an illogical ordering of messages and encourages
laziness and over-quoting. Those are the main reasons it is discouraged.
Compare this message to one in a thread with top-posting. This message
is organized, easy to follow, and requires little or no scrolling. The
top-posted message is likely followed by a dozen message going backward
in time, wrapping in inconvenient places do to excessive quote marks,
and taking up hundreds of lines for no good reason. It's nearly
impossible to determine who said what, and the order of the messages is
illogical.

Proper posting has huge advantages over top-posting. That's why we
insist on it, and you should too.

-Kevin
 
K

Kevin Goodsell

White said:
First: *all* of your classes *must* have a virtual destructor. They all
have virtual functions. Especially hashable and runnable *must* have
virtual destructors.

Or protected destructors, as Ivan pointed out.

-Kevin
 
M

Marcin Vorbrodt

White Wolf said:
First: *all* of your classes *must* have a virtual destructor. They all
have virtual functions. Especially hashable and runnable *must* have
virtual destructors.

Second: the advantage is less typing. You do not need to say "public:"


So it is just as i expected. You still need virtual destructors, so that
base pointers to derived objects get deleted properly right? Even if there
are no actual data fields in the base struct?


Thanks,
Martin
 
W

White Wolf

Marcin Vorbrodt wrote:
[SNIP]
So it is just as i expected. You still need virtual destructors, so
that base pointers to derived objects get deleted properly right?
Even if there are no actual data fields in the base struct?

Especially then. If there is no data in the base (pure interface class),
then it is even more important. Why? Because if you do not have any
members in the made, then (when deleting an object via a base pointer) *no*
members will be destructed. And it is very veyr likely that your
implementation classes *will* have members.
 
T

Thomas J. Clancy

Kevin Goodsell said:
It applies to all one-to-many communications on the net, not just
newsgroups. See RFC 1855. It's also not a "quirk", it is a standard.

I know its a standard, but still I maintain that it is quirky. :)
However, although I could come up with any number of counter arguments,
including examples, of why top-posting could be prefereable to "proper
posting," I would rather just move on and obey the standard and just enjoy
these newsgroups. Besides, my view of the entire issue might be completely
distorted and perhaps proper posting is the better way afterall. Still,
despite the fact that I disagree with the standard doesn't mean that I
cannot follow it, correct? :)

<soapbox>
To summarize: If we were to follow blindly and consistently all standards,
rules, laws, etc., there would be no innovation nor outlet for creative
thinking and reasoning, and eventually we'd find ourselves bound to a
totalitarian system that would, should we deviate event slightly from its
narrow, yet clearly marked paths, see to it that we are severely punished.
</soapbox>
 
T

Tim

White Wolf said:
Marcin Vorbrodt wrote:
[SNIP]
So it is just as i expected. You still need virtual destructors, so
that base pointers to derived objects get deleted properly right?
Even if there are no actual data fields in the base struct?

Especially then. If there is no data in the base (pure interface class),
then it is even more important. Why? Because if you do not have any
members in the made, then (when deleting an object via a base pointer) *no*
members will be destructed. And it is very veyr likely that your
implementation classes *will* have members.

....but isn't Marcin trying to find out if it's safe to NOT have a destructor
in his interface that he passes to clients? For a client to do a delete on
the interface and not have the concrete class's data destroyed is a positive
advantage is it not; the concrete class that hands out these interface needs
to be in control of its data's life-time through refrence counting or some
other means.

Isn't this like a light version of COM? A server hands out abstract
interfaces to clients; the client should not be able to delete the concrete
class by deleting the interface. In this particular case, the interface NOT
having a virtual destructor is just what you want; a delete on it will do
absolutely nothing since it has no allocated memory... assuming that the
concrete class wasn't 'new'd.
 
L

llewelly

Tim said:
White Wolf said:
Marcin Vorbrodt wrote:
[SNIP]
So it is just as i expected. You still need virtual destructors, so
that base pointers to derived objects get deleted properly right?
Even if there are no actual data fields in the base struct?

Especially then. If there is no data in the base (pure interface class),
then it is even more important. Why? Because if you do not have any
members in the made, then (when deleting an object via a base pointer) *no*
members will be destructed.

Nowhere is this guaranteed. If you have:

struct interface
{
virtual void foo()= 0;
};

struct imp : interface {vector<int> a;};

int main()
{
interface* p= new imp;
delete p;
}

you have _undefined_ behavior. The implementation may destruct a. It
may corrupt the heap. It may throw an exception. It may abort,
etc. Others may tell you the implementation may email your boss,
or cause a demon to emerge from your left nostril, but I will
constrain my list to things I have actually observed with real
implementations. :)
And it is very veyr likely that your

...but isn't Marcin trying to find out if it's safe to NOT have a destructor
in his interface that he passes to clients?

The only way to not have a destructor in one's interface is to declare
it private or protected. If no destructor is declared, one will be
generated. If the destructor is declared private or protected, the
destructor can only be used in certain places, reducting the
chance that someone will mistakenly call delete where the
pointer's type is inconsistent with the object's dynamic type. If
the destructor is also not defined, any use of delete will result
in a link error. IOWs, my above example is dangerous in part
because it *does* have a destructor. Had I written:

struct interface
{
virtual void foo()= 0;
private:
~interface();
};

//No definition of interface::~interface() ...
//Rest same as before ..

linking the code would result in an error, if delete was used on
an interface*. Since the error prevents misuse of delete, this is
in some sense 'safe', though some other way to release memory
blocks (e.g., a garbage collector) is likely needed.
For a client to do a delete on
the interface and not have the concrete class's data destroyed is a positive
advantage is it not;
[snip]

If that were guaranteed, I am sure someone could find a use for
it. However, it is not guaranteed.
 
R

Ron Natalie

White Wolf said:
First: *all* of your classes *must* have a virtual destructor. They all
have virtual functions. Especially hashable and runnable *must* have
virtual destructors.

Not necessarily true. Do not confuse "rules of thumb" with the MUST rules
of the language. The only time you need a virtual destructor is when derived
classes are deleted through pointers of their base types.
 
M

Mike Smith

Ivan said:
As Thomas mentioned, this only saves you from having to add
a 'public:' specification. Except for the public access
specifications, all uses of keyword 'struct' can be relaced
by 'class' in C++.

Or vice versa - one could argue that the "class" keyword was never
necessary at all, whereas "struct", of course, was already pre-existing
in C.
 
D

Dave Theese

Actually, there is one other thing to look out for...

When inheriting, if you don't specify public, inherited or private, the
default will be different depending on whether you inherit from a struct or
class. When inheriting from a struct, it will be public inheritance; when
inheriting from a class, it will be private inheritance.

So, if you replaced all "struct"s with "class"es and added "public" access
specifications as necessary to make all access rights equivalent to what
they were before, it is still possible for the meaning of a program to
change. Specifically, some public inheritance might change to private
inheritance, as stated above...
 
R

Ron Natalie

Dave said:
When inheriting, if you don't specify public, inherited or private, the
default will be different depending on whether you inherit from a struct or
class. When inheriting from a struct, it will be public inheritance; when
inheriting from a class, it will be private inheritance.

No, it doesn't work that way. It doesn't matter whether the class you are
inheritting from was defined with struct or class. What matters is the key
used to define the derived class.

struct X; // or class X; it doesn't matter

struct Y : X { } ; // Public inheritance
class Y : X { } ; // Private inheritance.
So, if you replaced all "struct"s with "class"es and added "public" access
specifications as necessary to make all access rights equivalent to what
they were before, it is still possible for the meaning of a program to
change. Specifically, some public inheritance might change to private
inheritance, as stated above...

Nope, you just have to make sure you put in enough public keys

struct Y : X { ...
is equivielent to
class Y : public X {
public: ...
 

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

No members online now.

Forum statistics

Threads
474,141
Messages
2,570,817
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top