473,378 Members | 1,507 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,378 software developers and data experts.

questions about virtual functions and abstract classes

Hello,

If I have a class that has virtual but non-pure declarations, like

class A{
virtual void f();
};

Then is A still an abstract class? Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
as not giving its definition, is this right?

In addition, if I have a virtual destructor for an abstract class A,
then why do I still have to define it? For example, if I have

class B{
virtual ~B();
virtual void f() = 0;
};

Then my compiler still asks me to define ~B(). However, I will never
create an object of type B!

Additionally, I don't think I can declare virtual constructor, but it
seems I can't make a pure constructor like

class C{
C() = 0;
virtual void f()=0;
};

Again, if I never make an object of type C, why am I not allowed to
declare the constructor pure?

Moreover, is there any function or operator that can't be virtual,
just like constructors?

Thanks!
Jess

Jun 19 '07 #1
17 3493
Jess wrote:
If I have a class that has virtual but non-pure declarations, like

class A{
virtual void f();
};

Then is A still an abstract class?
No, it's not. Only classes with at least one virtual function that is
declared pure (whether its own or inherited) are abstract.
Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
as not giving its definition, is this right?
No, it's not right. A pure function does not have to have a definition,
but it may. A non-pure virtual function _must_ be defined.
In addition, if I have a virtual destructor for an abstract class A,
then why do I still have to define it?
Because the language Standard requires you to.
For example, if I have

class B{
virtual ~B();
virtual void f() = 0;
};

Then my compiler still asks me to define ~B(). However, I will never
create an object of type B!
You will never create it _stand-alone_. You still can create it as
a subobject of a derived class.
Additionally, I don't think I can declare virtual constructor, but it
seems I can't make a pure constructor like

class C{
C() = 0;
virtual void f()=0;
};
The pure specifiers only apply to virtual functions.
Again, if I never make an object of type C, why am I not allowed to
declare the constructor pure?
Becuase only a virtual function can be declared pure.
Moreover, is there any function or operator that can't be virtual,
just like constructors?
Static member functions cannot be virtual. Since 'operator new'
and 'operator delete' are implicitly static, they cannot be virtual.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 19 '07 #2
Thanks a lot!

On Jun 19, 11:02 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Jess wrote:
If I have a class that has virtual but non-pure declarations, like
class A{
virtual void f();
};
Then is A still an abstract class?

No, it's not. Only classes with at least one virtual function that is
declared pure (whether its own or inherited) are abstract.
Can a pure-function be non-virtual? I tried an example and my compiler
says no.
Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
as not giving its definition, is this right?

No, it's not right. A pure function does not have to have a definition,
but it may. A non-pure virtual function _must_ be defined.
I see, so I can declare a pure virtual function in a class and define
it later as in

class A{
virtual void f() = 0;
};

void A::f(){...}
In addition, if I have a virtual destructor for an abstract class A,
then why do I still have to define it?

Because the language Standard requires you to.
For example, if I have
class B{
virtual ~B();
virtual void f() = 0;
};
Then my compiler still asks me to define ~B(). However, I will never
create an object of type B!

You will never create it _stand-alone_. You still can create it as
a subobject of a derived class.
Additionally, I don't think I can declare virtual constructor, but it
seems I can't make a pure constructor like
class C{
C() = 0;
virtual void f()=0;
};

The pure specifiers only apply to virtual functions.
Again, if I never make an object of type C, why am I not allowed to
declare the constructor pure?

Becuase only a virtual function can be declared pure.
Moreover, is there any function or operator that can't be virtual,
just like constructors?

Static member functions cannot be virtual. Since 'operator new'
and 'operator delete' are implicitly static, they cannot be virtual.
In that case, if I'd like a static member function to have polymorphic
behaviour, I think I need the static function to take an argument that
is a pointer to the base class object. Since this would allow the
static function to invoke an appropriate virtual function through the
pointer. Is this a correct approach?

Thanks,
Jess

Jun 19 '07 #3
On 2007-06-19 14:32, Jess wrote:
Hello,

If I have a class that has virtual but non-pure declarations, like

class A{
virtual void f();
};

Then is A still an abstract class? Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
as not giving its definition, is this right?
A class is abstract if you can not create an instance of it (which
happens when at least one of it's members are pure virtual). Consider
these the classes:

class NotAbstract {
virtual void foo() { /* ... */ }
virtual void bar() { /* ... */ }
};

class Abstract {
virtual void foo() = 0;
virtual void bar() { /* ... */ }
};

class PureAbstract {
virtual void foo() = 0;
virtual void bar() = 0;
};
In addition, if I have a virtual destructor for an abstract class A,
then why do I still have to define it? For example, if I have

class B{
virtual ~B();
virtual void f() = 0;
};

Then my compiler still asks me to define ~B(). However, I will never
create an object of type B!
Because by not adding =0 you tell the compiler that you will supply a
definition of the destructor.
Additionally, I don't think I can declare virtual constructor, but it
seems I can't make a pure constructor like

class C{
C() = 0;
virtual void f()=0;
};

Again, if I never make an object of type C, why am I not allowed to
declare the constructor pure?

Moreover, is there any function or operator that can't be virtual,
just like constructors?
If you'll never going to create an object of type B, what would you need
a constructor for?

If you are trying to create a pure abstract class then they generally
look like this:

class Abstract {
virtual void foo() = 0;
virtual int bar(float) = 0;
// ..
virtual ~Abstract() = 0;
}

--
Erik Wikström
Jun 19 '07 #4
Jess wrote:
Thanks a lot!
You're welcome.
On Jun 19, 11:02 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
>Jess wrote:
>>If I have a class that has virtual but non-pure declarations, like
>>class A{
virtual void f();
};
>>Then is A still an abstract class?

No, it's not. Only classes with at least one virtual function that
is declared pure (whether its own or inherited) are abstract.

Can a pure-function be non-virtual? I tried an example and my compiler
says no.
Right. Trust your compiler on this.
>> Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
as not giving its definition, is this right?

No, it's not right. A pure function does not have to have a
definition, but it may. A non-pure virtual function _must_ be
defined.

I see, so I can declare a pure virtual function in a class and define
it later as in

class A{
virtual void f() = 0;
};

void A::f(){...}
Yes, you may.
>[..static member functions cannot be virtual..]

In that case, if I'd like a static member function to have polymorphic
behaviour, I think I need the static function to take an argument that
is a pointer to the base class object. Since this would allow the
static function to invoke an appropriate virtual function through the
pointer. Is this a correct approach?

Uh... Well, yes, but that's not really "polymorphic behaviour" of the
static function. The static function will invoke polymorphic behaviour
of the object. If you need a member function to have polymorphic
behaviour, it has to be non-static and then the object parameter is
implicit. It's just the terminology we use.

If you're curious, you should look for "static virtual" discussions in
the news archives. There is a valid case where a static virtual could
have its place. But let's not start this discussion again, shall we?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 19 '07 #5
On Jun 19, 11:42 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Jess wrote:
Thanks a lot!

You're welcome.
On Jun 19, 11:02 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Jess wrote:
If I have a class that has virtual but non-pure declarations, like
>class A{
virtual void f();
};
>Then is A still an abstract class?
No, it's not. Only classes with at least one virtual function that
is declared pure (whether its own or inherited) are abstract.
Can a pure-function be non-virtual? I tried an example and my compiler
says no.

Right. Trust your compiler on this.
> Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
as not giving its definition, is this right?
No, it's not right. A pure function does not have to have a
definition, but it may. A non-pure virtual function _must_ be
defined.
I see, so I can declare a pure virtual function in a class and define
it later as in
class A{
virtual void f() = 0;
};
void A::f(){...}

Yes, you may.
[..static member functions cannot be virtual..]
In that case, if I'd like a static member function to have polymorphic
behaviour, I think I need the static function to take an argument that
is a pointer to the base class object. Since this would allow the
static function to invoke an appropriate virtual function through the
pointer. Is this a correct approach?

Uh... Well, yes, but that's not really "polymorphic behaviour" of the
static function. The static function will invoke polymorphic behaviour
of the object. If you need a member function to have polymorphic
behaviour, it has to be non-static and then the object parameter is
implicit. It's just the terminology we use.

If you're curious, you should look for "static virtual" discussions in
the news archives. There is a valid case where a static virtual could
have its place. But let's not start this discussion again, shall we?
Certainly! Thanks. :)
Jess
Jun 19 '07 #6
On Jun 19, 11:20 pm, Erik Wikström <Erik-wikst...@telia.comwrote:
On 2007-06-19 14:32, Jess wrote:
Hello,
If I have a class that has virtual but non-pure declarations, like
class A{
virtual void f();
};
Then is A still an abstract class? Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
as not giving its definition, is this right?

A class is abstract if you can not create an instance of it (which
happens when at least one of it's members are pure virtual). Consider
these the classes:

class NotAbstract {
virtual void foo() { /* ... */ }
virtual void bar() { /* ... */ }

};

class Abstract {
virtual void foo() = 0;
virtual void bar() { /* ... */ }

};

class PureAbstract {
virtual void foo() = 0;
virtual void bar() = 0;

};
Thanks! I'm just a bit curious: is there any particular situation
when I should prefer classes like PureAbstract over Abstract (or the
other way round)?
Jess

Jun 19 '07 #7
Jess wrote:
On Jun 19, 11:20 pm, Erik Wikström <Erik-wikst...@telia.comwrote:
>On 2007-06-19 14:32, Jess wrote:
>>Hello,
>>If I have a class that has virtual but non-pure declarations, like
>>class A{
virtual void f();
};
>>Then is A still an abstract class? Do I have to have "virtual void
f() = 0;" instead? I think declaring a function as "=0" is the same
as not giving its definition, is this right?

A class is abstract if you can not create an instance of it (which
happens when at least one of it's members are pure virtual). Consider
these the classes:

class NotAbstract {
virtual void foo() { /* ... */ }
virtual void bar() { /* ... */ }

};

class Abstract {
virtual void foo() = 0;
virtual void bar() { /* ... */ }

};

class PureAbstract {
virtual void foo() = 0;
virtual void bar() = 0;

};

Thanks! I'm just a bit curious: is there any particular situation
when I should prefer classes like PureAbstract over Abstract (or the
other way round)?
Purists (pun intended) would insist on defining all your base classes
like 'PureAbstract' in your example. Generally speaking, if there can
be a "default" behaviour for a virtual function, you should put it in
the base class, IMO, so that function is non-pure.

There are several idioms related to all this. For example, to make
a class abstract, yet fully defined, you only need to make its d-tor
pure (you still need to define it). That would prevent such class
from being instatiated, but you won't have to redefine any of its
behaviour if you don't want to.

The rule I try to follow is, "only make those functions pure that you
don't have a defined behaviour for". So, it's different for every
case.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Jun 19 '07 #8
On Jun 19, 2:32 pm, Jess <w...@hotmail.comwrote:
If I have a class that has virtual but non-pure declarations, like
class A{
virtual void f();
};
Then is A still an abstract class?
No.
Do I have to have "virtual void
f() = 0;" instead?
If you want the class to be abstract. Doing so has other
repercusions, however.

In practice, "abstract" represents a restriction on what can be
done with the class. It's never something you absolutely need
from a programming point of view; the fact that a class is
abstract is rather a consequence of the fact that you need pure
virtual functions.
I think declaring a function as "=0" is the same
as not giving its definition, is this right?
Not at all. The rules are far more subtle. Declaring a
function pure virtual (i.e. appending "= 0" to its declaration)
has several effects:

1. it makes the class abstract,

2. it means that anytime dynamic lookup of the function
resolves to the function in this class, you have undefined
behavior, and

3. it means that you are not required to provide a definition
of the function unless it is explicitly called.

Concerning these points;

1. You cannot create an instance of an abstract class.
Attention, however. This does not mean that there are never
objects which have the dynamic type of the class. During
construction and destruction, the dynamic type evolves to
alway be that of the constructor or destructor. So if you
call a pure virtual function (directly or indirectly) while
executing the constructor or the destructor, the dynamic
resolution will result in the pure virtual function. Which
leads to point 2:

2. It's undefined behavior. From a quality of implementation
point of view, I would expect the program to abort, with an
error message, and this is, in fact, what most compilers do.
But it's not guaranteed, and you cannot count on it.
Literally anything can happen, and you must absolutely avoid
the case.

3. Normally, if a function is virtual, it is considered to be
used, regardless of whether you ever actually call it or
not. And if a function is used, it must defined, somewhere.
If a function is pure virtual, however, it is not
automatically considered used, and so a definition is only
required if you actually do use it; since it cannot be found
by dynamic lookup (point 2), the only way to use it is to
call it explicitly, i.e. Base::f(). Note that the compiler
will generate such calls to the same function in the base
class implicitly in constructors, the destructor, and in a
compiler generated assignment operator. The constructors
are irrelevant here, since you cannot have a pure virtual
constructor, but if you have a pure virtual destructor, you
will have to provide a definition, and if you have a pure
virtual assignment operator (which I definitly don't
recommend), you will have to provide a definition if any of
the derived classes wants to use the default assignment
operator.
In addition, if I have a virtual destructor for an abstract class A,
then why do I still have to define it?
Because the compiler will generate a call to it in the
destructor of derived class, see point 3 above.
For example, if I have
class B{
virtual ~B();
virtual void f() = 0;
};
Then my compiler still asks me to define ~B(). However, I
will never create an object of type B!
No, but the compiler generates calls to the destructor in the
destructors of the derived classes. If you never derive from B,
you don't have to provide a definition of ~B(), but if you can't
instantiate the class, and you can't derive from it, what can
you do with it.
Additionally, I don't think I can declare virtual constructor,
but it seems I can't make a pure constructor like
class C{
C() = 0;
virtual void f()=0;
};
You can only make a virtual function pure. Since constructors
can't be virtual, they can't be pure.
Again, if I never make an object of type C, why am I not allowed to
declare the constructor pure?
Because constructors aren't virtual.
Moreover, is there any function or operator that can't be virtual,
just like constructors?
Static functions, including member operator new() and member
operator delete().

The above is rather abstract. Perhaps a quick explination of
the motivation behind it, or rather, how a compiler typically
implements it, would help:

The usual implementation of virtual functions (forgetting
multiple inheritance, etc., for the moment) is to define a table
of "function addresses" (in quotes, because we're at the
assembler level here, and this has nothing to do with any C++
type) for each class with at least one virtual function, and to
add a hidden pointer to this table in each class. (The table is
traditionally refered to as a vtbl, and the pointer as vptr,
from their names in the CFront generated C code.) A virtual
function is always considered "used" because the compiler must
take its address (which requires a definition) in order to
generate the vtbl. The point of declaring a function pure
virtual is to tell the compiler that it will not be called for
an object of this type, so the compiler does not need to take
its address and put it in the vtbl. (One early compiler I used
put a null pointer in its place, so the program silently died.
Most modern compilers put the address of a special function,
which outputs an error message and aborts, so you know why the
program died. And optimization may cause other effects.)
Because the compiler doesn't need the address for the vtbl, you
don't have to provide a definition.
>From the compiler point of view, there would be no problem
allowing the instantiation of a class with a pure virtual
function. But a virtual function which you cannot call
virtually is almost certainly an error, so the language declares
the class abstract, and forbids its instantiation.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 20 '07 #9
On Jun 19, 4:13 pm, "Victor Bazarov" <v.Abaza...@comAcast.netwrote:
Jess wrote:
On Jun 19, 11:20 pm, Erik Wikström <Erik-wikst...@telia.comwrote:
[...]
class NotAbstract {
virtual void foo() { /* ... */ }
virtual void bar() { /* ... */ }
};
class Abstract {
virtual void foo() = 0;
virtual void bar() { /* ... */ }
};
class PureAbstract {
virtual void foo() = 0;
virtual void bar() = 0;
};
Thanks! I'm just a bit curious: is there any particular situation
when I should prefer classes like PureAbstract over Abstract (or the
other way round)?
Purists (pun intended) would insist on defining all your base classes
like 'PureAbstract' in your example.
Then they reject the template method pattern, and most of what
was done in Smalltalk. (But I fear you're right, and that there
are people who insist on such things.)

In general, I've not heard the name pure abstract class, but
rather interface, for such classes. Probably an influence from
Java, which has a special keyword for such classes, and allows
multiple inheritance from them (but not from other classes). In
practice, of course, most real interfaces will want to define a
contract, which means that the public functions will be
non-virtual, forwarding to private (or protected) pure virtual
functions.
Generally speaking, if there can
be a "default" behaviour for a virtual function, you should put it in
the base class, IMO, so that function is non-pure.
Not necessarily. There are three possibilities:

-- The base class offers no default behavior. Classical pure
virtual, without an implementation.

-- The base class offers a default behavior, but requires that
the derived class use it explicitly. Pure virtual function
with an implementation; if the derived class wants the
default, it implements the function to simply call the base
class function.

-- The base class offers a default behavior which will be used
automatically if the derived class does nothing. Just a
normal virtual function.

(I'm not saying that the second possibility is really that
useful; I've never used it. But it does exist.)

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 20 '07 #10
Thanks a lot!

On Jun 20, 6:20 pm, James Kanze <james.ka...@gmail.comwrote:
On Jun 19, 2:32 pm, Jess <w...@hotmail.comwrote:
If I have a class that has virtual but non-pure declarations, like
class A{
virtual void f();
};
Then is A still an abstract class?

No.
Do I have to have "virtual void
f() = 0;" instead?

If you want the class to be abstract. Doing so has other
repercusions, however.

In practice, "abstract" represents a restriction on what can be
done with the class. It's never something you absolutely need
from a programming point of view; the fact that a class is
abstract is rather a consequence of the fact that you need pure
virtual functions.
I think declaring a function as "=0" is the same
as not giving its definition, is this right?

Not at all. The rules are far more subtle. Declaring a
function pure virtual (i.e. appending "= 0" to its declaration)
has several effects:

1. it makes the class abstract,

2. it means that anytime dynamic lookup of the function
resolves to the function in this class, you have undefined
behavior, and
If a function is pure virtual but I still define it, would the
compiler put the function's address into vtbl? If the compiler puts
the addr into the vtble, then I think it wouldn't cause an undefined
behaviour when this function is called.
3. it means that you are not required to provide a definition
of the function unless it is explicitly called.
By "explicitly called", do you mean the example like "Base::f()"
below?
Concerning these points;

1. You cannot create an instance of an abstract class.
Attention, however. This does not mean that there are never
objects which have the dynamic type of the class. During
construction and destruction, the dynamic type evolves to
alway be that of the constructor or destructor. So if you
call a pure virtual function (directly or indirectly) while
executing the constructor or the destructor, the dynamic
resolution will result in the pure virtual function. Which
leads to point 2:
I don't quite understand this...What is "dynamic types evolve to be
that of constructor or destructor" and how can a pure virtual function
be called in a constructor or destructor? I had an experiment

#include<iostream>

using namespace std;

class A{
public:
virtual ~A(){};
virtual void f()=0;
};

void A::f(){cout << "A::f()" << endl;}

class B:public A{
public:
int x;
B():x(10){f();}
void f(){cout << "B::f()" << endl;}
};
int main(){
B b;
return 0;
}

In the constructor B(), I called the virtual function f(). I remember
the book Effective C++ says if I call a virtual function (f()) in a
constructor (B()), then the function won't be resolved to B::f()
because the object is not yet of type B. Instead A::f() is called.
However, when I ran my program, I got B::f(). What happened?
>
2. It's undefined behavior. From a quality of implementation
point of view, I would expect the program to abort, with an
error message, and this is, in fact, what most compilers do.
But it's not guaranteed, and you cannot count on it.
Literally anything can happen, and you must absolutely avoid
the case.

3. Normally, if a function is virtual, it is considered to be
used, regardless of whether you ever actually call it or
not. And if a function is used, it must defined, somewhere.
If a function is pure virtual, however, it is not
automatically considered used, and so a definition is only
required if you actually do use it; since it cannot be found
by dynamic lookup (point 2), the only way to use it is to
call it explicitly, i.e. Base::f().
So even if the pure virtual function is defined, its addr is not put
into vtbl? Is the addr not stored at all, not in vtbl, not anywhere
else? By the way, is this why my program above got B::f() instead of
A::f()? However, even if A::f() isn't in the vtbl, I thought the
object being constructed isn't of type B yet, so its B::f() shouldn't
be called.

Note that the compiler
will generate such calls to the same function in the base
class implicitly in constructors, the destructor, and in a
compiler generated assignment operator.
Do you mean if I have a derived class B, base class A, then in B's
constructor, the compiler generates A::A(), in B's destructor it
generates A::~A() etc?

Thanks,
Jess

Jun 20 '07 #11
On Jun 20, 6:30 pm, James Kanze <james.ka...@gmail.comwrote:
In general, I've not heard the name pure abstract class, but
rather interface, for such classes. Probably an influence from
Java, which has a special keyword for such classes, and allows
multiple inheritance from them (but not from other classes). In
practice, of course, most real interfaces will want to define a
contract, which means that the public functions will be
non-virtual, forwarding to private (or protected) pure virtual
functions.
Why are public functions non-virtual? I thought an interface-
implementation would look like

class A{
public:
virtual void f() = 0;
virtual void g() = 0;
};

class B:public A{
public:
void f();
void g();
};

void B::f(){}
void B::g(){}

In other words, A declares a set of virtual functions and B inherits
from A and implements the virtual functions. Then a client program
can use A& or A* to do polymorphic operations. Is this not right? In
addition, when do we need to "forward to private (or protected) pure
virtual function"?

Thanks,
Jess

Jun 20 '07 #12
On 20 Jun, 12:12, Jess <w...@hotmail.comwrote:
On Jun 20, 6:30 pm, James Kanze <james.ka...@gmail.comwrote:
In general, I've not heard the name pure abstract class, but
rather interface, for such classes. Probably an influence from
Java, which has a special keyword for such classes, and allows
multiple inheritance from them (but not from other classes). In
practice, of course, most real interfaces will want to define a
contract, which means that the public functions will be
non-virtual, forwarding to private (or protected) pure virtual
functions.

Why are public functions non-virtual?
http://www.gotw.ca/publications/mill18.htm

Gavin Deane

Jun 20 '07 #13
On Jun 19, 8:18 am, Jess <w...@hotmail.comwrote:
Can a pure-function be non-virtual? I tried an example and my compiler
says no.
What would this mean? To me it would mean that all derived classes
must override this method, but since it is not virtual there is no
concept of overriding in the first place. This is why "pure" is tied
to "virtual". There is no pure without virtual, because only virtual
functions can be overriden.

I see, so I can declare a pure virtual function in a class and define
it later as in

class A{
virtual void f() = 0;

};

void A::f(){...}
Yes. This isn't very common but it's possible and useful sometimes.
If you find yourself doing this constantly, you may want to go back
and re-examine some of the design issues related to interfaces, pure
virtual functions, and abstract classes.

In addition, if I have a virtual destructor for an abstract class A,
then why do I still have to define it?
All classes must have a destructor defined. Just because you will
never create an object of type B doesn't mean you won't delete an
object through a B pointer.
Additionally, I don't think I can declare virtual constructor, but it
seems I can't make a pure constructor like
class C{
C() = 0;
virtual void f()=0;
};
Again, what would be the point? If you have a pure constructor but no
other pure virtual functions, then your class essentially does
nothing. If you have a pure virtual function but no pure constructor,
it works the same as if you did have a pure constructor.
Moreover, is there any function or operator that can't be virtual,
just like constructors?
Static member functions cannot be virtual. Since 'operator new'
and 'operator delete' are implicitly static, they cannot be virtual.

In that case, if I'd like a static member function to have polymorphic
behaviour, I think I need the static function to take an argument that
is a pointer to the base class object. Since this would allow the
static function to invoke an appropriate virtual function through the
pointer. Is this a correct approach?
static members can't be virtual because there is no "this" pointer.
there is no instance associated with a static function.

Jun 20 '07 #14
On Jun 20, 1:06 pm, Jess <w...@hotmail.comwrote:
On Jun 20, 6:20 pm, James Kanze <james.ka...@gmail.comwrote:
[...]
I think declaring a function as "=0" is the same
as not giving its definition, is this right?
Not at all. The rules are far more subtle. Declaring a
function pure virtual (i.e. appending "= 0" to its declaration)
has several effects:
1. it makes the class abstract,
2. it means that anytime dynamic lookup of the function
resolves to the function in this class, you have undefined
behavior, and
If a function is pure virtual but I still define it, would the
compiler put the function's address into vtbl?
Probably not, but if the compiled code ever has to look at that
entry in the vtbl, the program has undefined behavior, so
anything the compiler puts there is legal.
If the compiler puts the addr into the vtble, then I think it
wouldn't cause an undefined behaviour when this function is
called.
If the compiler documents that it puts the address there, then
they are defining undefined behavior. It's an extension. As I
said, most compilers put the address of a function which aborts
with an error message there. From a quality of implementation
point of view, that's probably the best solution.

Note that "undefined behavior", when used in this group,
normally refers to all behavior undefined by the language
specification, and doesn't take implementation specific
extensions into account. If the standard says that something is
undefined behavior, then it is undefined behavior regardless of
what the compiler does.
3. it means that you are not required to provide a definition
of the function unless it is explicitly called.
By "explicitly called", do you mean the example like "Base::f()"
below?
Yes. "Explicitly called" isn't really the correct expression, I
think. I should have said something like "called through a
qualified identifier", or something like that.
Concerning these points;
1. You cannot create an instance of an abstract class.
Attention, however. This does not mean that there are never
objects which have the dynamic type of the class. During
construction and destruction, the dynamic type evolves to
alway be that of the constructor or destructor. So if you
call a pure virtual function (directly or indirectly) while
executing the constructor or the destructor, the dynamic
resolution will result in the pure virtual function. Which
leads to point 2:
I don't quite understand this...What is "dynamic types evolve to be
that of constructor or destructor" and how can a pure virtual function
be called in a constructor or destructor?
The dynamic type of the object. Consider something like the
following:

class Base
{
public:
Base() ;
virtual void g() = 0 ;
} ;

class Middle : public Base
{
public:
Middle() ;
virtual void g()
{
std::cout << "Middle" << std::endl ;
}
} ;

class Derived : public Middle
{
public:
Derived() ;
virtual void g()
{
std::cout << "Derived" << std::endl ;
}
} ;

void
f( Base* p )
{
p->g() ;
}

Base::Base()
{
// f( this ) ; undefined behavior !!!
}

Middle::Middle()
{
f( this ) ; // should call Middle::g()
}

Derived::Derived()
{
f( this ) ; // should call Derived::g()
}

int
main()
{
Derived d ;
}

The function actually called in f depends on the dynamic type of
the object that p points to. As long as we are in the
constructor Middle::Middle(), even if the final type of the
object will be Derived, the object behaves as if it were only a
Middle. If you uncomment the call to f() in Base::Base, then
the program has undefined behavior; I get the message
pure virtual method called
terminate called without an active exception
Aborted
from g++. (But the standard doesn't require this. Undefined
behavior is, well, undefined.) Adding a definition for
Base::g() doesn't change this. (But if I add the definition,
calling Base::g() is perfectly well behaved. And if I don't
calling Base::g() causes an error at link time---although as far
as the standard is concerned, it's undefined behavior.)
I had an experiment
#include<iostream>
using namespace std;

class A{
public:
virtual ~A(){};
virtual void f()=0;
};
void A::f(){cout << "A::f()" << endl;}
class B:public A{
public:
int x;
B():x(10){f();}
void f(){cout << "B::f()" << endl;}
};
int main(){
B b;
return 0;
}
In the constructor B(), I called the virtual function f(). I remember
the book Effective C++ says if I call a virtual function (f()) in a
constructor (B()), then the function won't be resolved to B::f()
because the object is not yet of type B. Instead A::f() is called.
However, when I ran my program, I got B::f(). What happened?
I think you misunderstood something in Effective C++. When
calling f() in B::B(), it's exactly as if the type of the
complete object were B (which in this case it is). What will
cause problems is calling f() in A::A().
2. It's undefined behavior. From a quality of implementation
point of view, I would expect the program to abort, with an
error message, and this is, in fact, what most compilers do.
But it's not guaranteed, and you cannot count on it.
Literally anything can happen, and you must absolutely avoid
the case.
3. Normally, if a function is virtual, it is considered to be
used, regardless of whether you ever actually call it or
not. And if a function is used, it must defined, somewhere.
If a function is pure virtual, however, it is not
automatically considered used, and so a definition is only
required if you actually do use it; since it cannot be found
by dynamic lookup (point 2), the only way to use it is to
call it explicitly, i.e. Base::f().
So even if the pure virtual function is defined, its addr is
not put into vtbl?
Maybe. Anything you can do to find out whether it's there or
not is undefined behavior, so the compiler can do whatever it
wants. Most compilers will not put it in, since that could hide
an error.
Is the addr not stored at all, not in vtbl, not anywhere
else?
If you write Base::f(), then the address is stored somehow as
part of the call instruction. It's also likely stored in the
stack walkback tables for exception handling, and probably in
the debugging information. And anywhere else the compiler needs
it.
By the way, is this why my program above got B::f() instead of
A::f()? However, even if A::f() isn't in the vtbl, I thought the
object being constructed isn't of type B yet, so its B::f() shouldn't
be called.
Sort of:-). You're writing the constructor, and it is up to you
to know how far along you are in construction, and what
functions will or will not work. Most of the time, most
programmers try to do all critical initialization in the
constructor initializer list, so that once in the body of the
constructor, they have an object with consistent state, on which
they can usually call most functions. (Note the frequent use of
"most" and "usually" in the above. It's not an absolute rule,
and it must often be weighed against other considerations; I
frequently find myself violating it in templated constructors,
for example.)
Note that the compiler
will generate such calls to the same function in the base
class implicitly in constructors, the destructor, and in a
compiler generated assignment operator.
Do you mean if I have a derived class B, base class A, then in B's
constructor, the compiler generates A::A(), in B's destructor it
generates A::~A() etc?
Yes. It is, by definition, impossible to have an instance of A
without A's constructor having been called. Even if that
instance is only a base class subobject. Try my example above:
with the undefined behavior commented out, it prints:
Middle
Derived

I'm very surprised that you have to ask that. It's one of the
basics of C++, and should be covered by any book that explains
inheritance, no matter how simply.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 20 '07 #15
On Jun 20, 1:12 pm, Jess <w...@hotmail.comwrote:
On Jun 20, 6:30 pm, James Kanze <james.ka...@gmail.comwrote:
In general, I've not heard the name pure abstract class, but
rather interface, for such classes. Probably an influence from
Java, which has a special keyword for such classes, and allows
multiple inheritance from them (but not from other classes). In
practice, of course, most real interfaces will want to define a
contract, which means that the public functions will be
non-virtual, forwarding to private (or protected) pure virtual
functions.
Why are public functions non-virtual?
Because public functions define the contract, and defining the
contract is the responsibility of the base class.
I thought an interface- implementation would look like
class A{
public:
virtual void f() = 0;
virtual void g() = 0;
};
class B:public A{
public:
void f();
void g();
};
void B::f(){}
void B::g(){}
In other words, A declares a set of virtual functions and B inherits
from A and implements the virtual functions.
That's one way of doing it. Now suppose that f() actually
returns an int in the range 1...6. How do you enforce this in
the above schema. Whereas:

class A
{
public:
int f() {
int result = doF() ;
assert( result >= 1 && result <= 6 ) ;
return result ;
}

private:
virtual int doF() = 0 ;
} ;

There's no way a derived class will accidentally violate the
contract.
Then a client program
can use A& or A* to do polymorphic operations.
The problem is what the client program can count on. If A
guarantees that A::f() will return a value in the range 1...6,
and the client code counts on it, then if the derived class
implements "int B::f() { return 10 ; }", the client will not be
able to use it. C++ doesn't provide any built-in mechanism for
detecting this sort of thing; the above schema does.
Is this not right? In
addition, when do we need to "forward to private (or protected) pure
virtual function"?
Whenever you have a contract that goes beyond what can be
expressed in a simple function signature. Typically, this is
the case most of the time. The major exception are design
patterns involving an inversion of the call sequence---callbacks
and such in everyday language.

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 20 '07 #16
On Jun 21, 2:39 am, James Kanze <james.ka...@gmail.comwrote:
Sort of:-). You're writing the constructor, and it is up to you
to know how far along you are in construction, and what
functions will or will not work. Most of the time, most
programmers try to do all critical initialization in the
constructor initializer list, so that once in the body of the
constructor, they have an object with consistent state, on which
they can usually call most functions. (Note the frequent use of
"most" and "usually" in the above.
Thanks. :) I think in the constructor initializer list, we should
initialize the data members and probably call base class constructors.
What other "critical" initialization do we need to do there?
>
Note that the compiler
will generate such calls to the same function in the base
class implicitly in constructors, the destructor, and in a
compiler generated assignment operator.
Do you mean if I have a derived class B, base class A, then in B's
constructor, the compiler generates A::A(), in B's destructor it
generates A::~A() etc?

Yes. It is, by definition, impossible to have an instance of A
without A's constructor having been called. Even if that
instance is only a base class subobject. Try my example above:
with the undefined behavior commented out, it prints:
Middle
Derived

I'm very surprised that you have to ask that. It's one of the
basics of C++, and should be covered by any book that explains
inheritance, no matter how simply.
The books I read did say that. I was just not sure which "same
function" you refered to, so I probably asked a dumb question. :)
Jess

Jun 21 '07 #17
On Jun 21, 2:44 pm, Jess <w...@hotmail.comwrote:
On Jun 21, 2:39 am, James Kanze <james.ka...@gmail.comwrote:
Sort of:-). You're writing the constructor, and it is up to you
to know how far along you are in construction, and what
functions will or will not work. Most of the time, most
programmers try to do all critical initialization in the
constructor initializer list, so that once in the body of the
constructor, they have an object with consistent state, on which
they can usually call most functions. (Note the frequent use of
"most" and "usually" in the above.
Thanks. :) I think in the constructor initializer list, we should
initialize the data members and probably call base class constructors.
What other "critical" initialization do we need to do there?
Basically, you want to be sure that the class is in a state that
you can call member functions on it. This means that all base
classes and data members have been initialized. It shouldn't
mean anything more; at any rate, you can't do more than that in
the initializer list.

Note that the constructors for all base class and data members
*will* be called, whether they appear in the initializer list or
not. It's only important to put them in the initializer list
when the default constructor doesn't do what you want. (For
built-in types, of course, the default constructor doesn't do
anything, which is never what you want, so you'll always want to
initialize members with built-in type in the initializer list.)

Note to that initialization of the base classes and members
follows a pre-defined order, independantly of the order you
specify initialization in the initializer list. The order is:
1. Virtual base classes (only in the most derived class), in
the order they appear in a depth first left to right
traversal of the inheritance tree.
2. Immediate base classes, left to right.
3. Members, left to right.
(In the above, left to right means in the order the declarations
appear in the source code.) Some compilers will warn if the
initializers in the initialization list aren't in the same
order.
Note that the compiler
will generate such calls to the same function in the base
class implicitly in constructors, the destructor, and in a
compiler generated assignment operator.
Do you mean if I have a derived class B, base class A, then in B's
constructor, the compiler generates A::A(), in B's destructor it
generates A::~A() etc?
Yes. It is, by definition, impossible to have an instance of A
without A's constructor having been called. Even if that
instance is only a base class subobject. Try my example above:
with the undefined behavior commented out, it prints:
Middle
Derived
I'm very surprised that you have to ask that. It's one of the
basics of C++, and should be covered by any book that explains
inheritance, no matter how simply.
The books I read did say that. I was just not sure which "same
function" you refered to, so I probably asked a dumb question. :)
Not at all. I probably should have been clearer, since "same
function" isn't really very explicit here. What I meant was
simply that in the constructor, the compiler will generate calls
to the constructor, and in the destructor, calls to the
destructor. (But of course, A's constructor isn't the same
function as B's constructor, especially if they're both
overloaded.)

--
James Kanze (GABI Software, from CAI) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Jun 21 '07 #18

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: richard.forrest1 | last post by:
I have a problem with an abstract interface class whose implementation classes need to return different iterator types (but with the same value_types etc). Classes A and B both conform to the...
62
by: christopher diggins | last post by:
Since nobody responded to my earlier post , I thought I would try to explain what I am doing a bit differently. When multiply inheriting pure virtual (abstract) base classes, a class obviously...
10
by: Britney | last post by:
1. what are virutal functions and how are they differenet from overloaded function? 2. what are interfaces and how are they different from abstract classes?
6
by: Alden Pierre | last post by:
Hello, http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.7 As per the link above it's wise to have a virtual deconstructor when creating an abstract class. Here is when I'm...
7
by: eric | last post by:
hello i'm confused by an example in the book "Effective C++ Third Edition" and would be grateful for some help. here's the code: class Person { public: Person(); virtual ~Person(); // see...
14
by: v4vijayakumar | last post by:
Why we need "virtual private member functions"? Why it is not an (compile time) error?
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.