What's the different betteen pure virtual function and virtualfunction

J

Jack

Hi,

I meet a question with it ,

I did not get clear the different betteen them,

for example:

#include <iostream>

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

inline Base::~Base()
{}

inline void Base::pure()
{
std::cout << "Base::pure() called\n";
}

class Derived: public Base
{
public:
virtual void pure();
};

inline void Derived::pure()
{
Base::pure();
std::cout << "Derived::pure() called\n";
}

int main()
{
Derived derived;

derived.pure();
derived.Base::pure();

Derived *dp = &derived;

dp->pure();
dp->Base::pure();
}
 
L

Lars Uffmann

Jack said:
I did not get clear the different betteen them,

Given there's no errors in the code below (am not familiar enough with
virtual to know for sure on all the calls), I can provide my input:
for example:
[..]
virtual ~Base();
virtual void pure() = 0;
inline void Base::pure()
{
std::cout << "Base::pure() called\n";
}

I think the pure() = 0 assignment in the class definition has no effect
since you later define the function, actually I'm not even sure if it is
allowed by the compiler.
class Derived: public Base
{
public:
virtual void pure();
};

This defines the new function for Derived which gets called if you call
pure() for an object of type Derived.
inline void Derived::pure()
{
Base::pure();
std::cout << "Derived::pure() called\n";
}
This first calls the Base class pure() and then adds its own code.
derived.pure();
This calls Derived.pure() (which in turn calls Base.pure() first),
output will be:
Base::pure() called
Derived::pure() called
derived.Base::pure();
This calls Base.pure() for object derived, output
Base::pure() called
dp->pure();
dp->Base::pure();
These two calls do exactly the same, just with a pointer as variable,
instead of an object.

I'm not sure I understand your problem?

Lars
 
L

Lars Uffmann

Hi Daniel,

Just so I get to learn something from this:
First, pure virtual:

class Base1 {
public:
virtual void pure() = 0;
};

So _pure_ refers to a virtual function definition and the = 0 will allow
for class definition without an actualy function body declaration? And
then you may not use the base class, and also
class Derived1 { }; // will not compile
_must_ define the virtual function in the derived class that you want to
use?

And could you declare a pure virtual function, then derive another one
from that, then derive a third one and ONLY define the function body in
the third one, if that is the function you're going to use?
e.g.:
class Base { public: virtual void pure() = 0; };
class Derived : public Base { };
class TwiceDerived : public Derived { void pure() { cout << "twice
derived pure"; }

and then use
TwiceDerived td;
td.pure();
?

Best Regards,

Lars
 
D

dizzy

Daniel said:
First, pure virtual:

class Base1 {
public:
virtual void pure() = 0;
};

class Derived1 { }; // will not compile

Huh? On what compiler? You just defined an unrelated Derived1 class type.
You probably mean "class Derived1: public Base1 {};" but even in such a
case it will compile. It won't compile if you try to instantiate a Derived1
but you didn't say anything about instantiating it.
class Derived2 {
public:
void pure() { cout << "pure\n"; }
};

An unrelated Derived2 type that has a "void pure()" function. You probably
(again) mean "class Derived2: public Base1". In which case you will
override the pure virtual from Base1 and thus instances of Derived2 will be
allowed.
int main() {
Base1 b; // will not compile
}
Right.

Now virtual:

class Base1 {
public:
virtual void vert();
};

class Derived1 { }; // will compile

You mean "class Derived1: public Base1 {};" and "instantiating it will not
compile".
int main() {
Base1 b; // will compile
}
Right.

That's the difference.

Ok :)
 
J

Jerry Coffin

[ ... ]
First, pure virtual:

class Base1 {
public:
virtual void pure() = 0;
};

class Derived1 { }; // will not compile

Of course it will. Right now, the 'Derived' part of the name is a lie --
this isn't derived from anything; it's just an empty class, which will
compile just fine.

Even if Derived1 was derived from Base1, it would still compile:

class Derived1 : public Base1 { }; // will compile

What _won't_ compile is if you attempt to _instantiate_ an object of
this type:

Derived1 x; // will NOT compile.

A pure virtual function does _not_ imply that every derived class must
override that function. Rather, it implies that when/if an object of a
derived class is instantiated, that _some_ class must have overridden
the virtual function. In some cases, it's quite reasonable to have two
(or more) levels of derivation, including an intermediate class that
does NOT override a pure virtual function declared in the base class:

#include <iostream>

class Base2 {
public:
virtual void pure() = 0;
};

class Derived2 : public Base2 {
public:
virtual void pure2() = 0;
};

class DoublyDerived2 : public Derived2 {
public:
void pure() { std::cout << "dd2_pure()\n"; }
void pure2() { std::cout << "dd2_pure2()\n"; }
};

class DoublyDerived3 : public Derived2 {
public:
void pure() { std::cout << "dd3_pure()\n"; }
void pure2() { std::cout << "dd3_pure2()\n"; }
};

As it stands, this probably doesn't make a lot of sense, so let me try
to make the example a bit more concrete:

namespace database {
class generic {
public:
virtual void open(char const *) = 0;
};

class SQL {
public:
cursor exec_query(char const *) = 0;
};

class Oracle : public SQL {
public:
// these two functions actually have to be implemented.
void open(char const *db_name);
cursor exec_query(char const *query);
};

class Postgres : public SQL {
/* like Oracle */
};

class MySQL : public SQL {
/* like Oracle */
};

class Paradox : public generic {
void open(char const *db_name) {
/* ... */
}
};

}

We can never (even attempt to) create an object of the SQL class -- but
the SQL class can exist (and provide utility) without overriding the
pure-virtual function in the base class. We can create objects of the
Postgres, Oracle or MySQL classes, and we can have a SQL* point at one,
or a SQL& refer to one.
 
J

Juha Nieminen

Lars said:
Jack said:
I did not get clear the different betteen them,

Given there's no errors in the code below (am not familiar enough with
virtual to know for sure on all the calls), I can provide my input:
for example:
[..]
virtual ~Base();
virtual void pure() = 0;
inline void Base::pure()
{
std::cout << "Base::pure() called\n";
}

I think the pure() = 0 assignment in the class definition has no effect
since you later define the function, actually I'm not even sure if it is
allowed by the compiler.

Maybe you should familiarize yourself with pure virtual functions
before giving answers about things you don't know?

"virtual void pure() = 0;" is not an assignment. It's just a syntax
for declaring a pure virtual function (AFAIK the story of this goes
something like the C++ standardization committee not wanting to create
yet another reserved keyword for only this purpose).

It's perfectly valid to give a pure virtual function an
implementation. The function will still be purely virtual (ie. the class
must be inherited to instantiate it), but the implementation can be
called explicitly.
 
J

Juha Nieminen

Lars said:
So _pure_ refers to a virtual function definition and the = 0 will allow
for class definition without an actualy function body declaration?

No. A pure virtual function is one which must be reimplemented in a
derived class. The "=0" is just syntactical notation to say that.
(Imagine it being a keyword like "pure" instead.)

The "=0" has nothing to do with whether you have to implement the
function or not. Any function can be declared but not implemented. (It's
just that if you try to call the function and it's not implemented,
you'll get a linker error.)
 
T

Thomas J. Gritzan

Juha said:
Lars said:
Jack said:
I did not get clear the different betteen them,
Given there's no errors in the code below (am not familiar enough with
virtual to know for sure on all the calls), I can provide my input:
for example:
[..]
virtual ~Base();
virtual void pure() = 0;
inline void Base::pure()
{
std::cout << "Base::pure() called\n";
}
I think the pure() = 0 assignment in the class definition has no effect
since you later define the function, actually I'm not even sure if it is
allowed by the compiler.

Maybe you should familiarize yourself with pure virtual functions
before giving answers about things you don't know?

"virtual void pure() = 0;" is not an assignment. It's just a syntax
for declaring a pure virtual function (AFAIK the story of this goes
something like the C++ standardization committee not wanting to create
yet another reserved keyword for only this purpose).

"void" would be nice:

virtual void pure(void) void; // not serious!
It's perfectly valid to give a pure virtual function an
implementation. The function will still be purely virtual (ie. the class
must be inherited to instantiate it), but the implementation can be
called explicitly.

Just to add:
In one case, you _have to_ give an implementation: In a pure virtual
destructor. Since the destructor of a derived class will call all its
base class destructors recursively, you need an implementation for all
destructors, even for pure ones.
 
L

Lars Uffmann

Juha said:
Maybe you should familiarize yourself with pure virtual functions
before giving answers about things you don't know?

Maybe you should learn some basic politeness. And then not blurt out
assumptions like the one that seems to have driven you to this comment:
"virtual void pure() = 0;" is not an assignment.

Now where did I state I thought this to be an assignment? My "allowed by
the compiler" was referring to his pure() = 0 being followed by a
declaration of that very pure virtual function. As stated in my last
post. So - from my understanding, you not only managed to miss that
point AND correct me on something that didn't need correction, you also
failed at basic friendly communication... This is especially annoying
because I clearly stated that I wasn't an expert on the matter, and was
trying to be helpful anyways.

Hey - if you have a bad day, take it somewhere else, okay?

Sheesh...

Lars
 
J

James Kanze

First, pure virtual:
class Base1 {
public:
virtual void pure() = 0;
};
class Derived1 { }; // will not compile

Why not? Derived1 is still abstract, so you can't instantiate
it, but you can still define it (and use it as a base class for
further derivation).

Declaring a member function pure virtual has three effects:

1. you're not required to define it (but you are allowed to);
2. you cannot instantiate an instance of a class with a pure
virtual function; and
3. if dynamic resolution resolves to the pure virtual function,
your code has undefined behavior (and with most compilers,
will crash).

Thus, for 1:

class Base
{
public:
virtual void notPure() ;
} ;

class Derived
{
public:
virtual void notPure() {}
} ;

int
main()
{
Derived b ;
}

has undefined behavior (and will often fail at link), because
you have not defined Base::notPure, and this despite the fact
that you never call Base::notPure. Making Base::notPure pure
renders the code legal.

For 2:

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

int
main()
{
Base b ;
}

will not compile, because the class Base is abstract.

For 3:

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

class Derived
{
public:
virtual void pure() {}
} ;

int
main()
{
Derived d ;
}

has undefined behavior, because the call to pure() in Base
resolves to Base::pure(), which is pure virtual. Note that this
remains true even if you define Base::pure(). With most
compilers, this code will crash on execution (but you can't
count on it, since the behavior is undefined).
 
L

Lars Uffmann

Daniel said:
That's part of it. Making the function pure (i.e., putting the "=0" at
the end,) means you don't have to define the function for that class
(you can if you want though.)
> [..more useful information..]

Thank you! :)
 
J

James Kanze

No. A pure virtual function is one which must be reimplemented
in a derived class. The "=0" is just syntactical notation to
say that. (Imagine it being a keyword like "pure" instead.)

You're right that the =0 is just syntactical notation (but it is
two separate tokens...you can insert white space between the two
characters, or even comments). But there's more to it than you
seem to be saying.
The "=0" has nothing to do with whether you have to implement
the function or not. Any function can be declared but not
implemented. (It's just that if you try to call the function
and it's not implemented, you'll get a linker error.)

Again, the rules are a bit more complicted. A function must be
implemented if it is "used". A function is used if it is
called, of course, or if its address is taken, but a virtual
function is also "used" anytime you create an instance of the
class, or of a class derived from it, unless it is pure. Making
a virtual function pure frees you from the obligation of having
to implement it (amongst other things).
 

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
473,769
Messages
2,569,582
Members
45,066
Latest member
VytoKetoReviews

Latest Threads

Top