473,703 Members | 3,018 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Pure virtual destructor

Hello,
I was going through the Marshal Cline's C++ FAQ-Lite.

I have a doubt regarding section 33.10.

Here he is declaring a pure virtual destructor in the base class.

And again defining it inline. Like this.

inline Funct::~Funct() { } // defined even though it's pure virtual; it's
faster this way; trust me

My doubt is:

1.. Why we should make destructors pure virtual. What is the advantage?
2.. If it is pure virtual, there should not any definition of it in the
base class. It should be only defined in derived class, so that we can
create the instance of derived class.
3.. But in this case it is not redefined in derived class. What is the
reason?
4.. Again how it is fasted to make it define inline in Base class? Because
inline request will not be obeyed by compiler, if it is virtual.
I am attaching the 33.10 section of FAQ for your reference.

[33.10] What the heck is a functionoid, and why would I use one?

Functionoids are functions on steroids. Functionoids are strictly more
powerful than functions, and that extra power solves some (not all) of the
challenges typically faced when you use function-pointers.

Let's work an example showing a traditional use of function-pointers, then
we'll translate that example into functionoids. The traditional
function-pointer idea is to have a bunch of compatible functions:

int funct1(...param s...) { ...code... }
int funct2(...param s...) { ...code... }
int funct3(...param s...) { ...code... }

Then you access those by function-pointers:

typedef int(*FunctPtr)( ...params...);

void myCode(FunctPtr f)
{
...
f(...args-go-here...);
...
}

Sometimes people create an array of these function-pointers:

FunctPtr array[10];
array[0] = funct1;
array[1] = funct1;
array[2] = funct3;
array[3] = funct2;
...

In which case they call the function by accessing the array:

array[i](...args-go-here...);

With functionoids, you first create a base class with a pure-virtual method:

class Funct {
public:
virtual int doit(int x) = 0;
virtual ~Funct() = 0;
};

inline Funct::~Funct() { } // defined even though it's pure virtual; it's
faster this way; trust me

Then instead of three functions, you create three derived classes:

class Funct1 : public Funct {
public:
virtual int doit(int x) { ...code from funct1... }
};

class Funct2 : public Funct {
public:
virtual int doit(int x) { ...code from funct2... }
};

class Funct3 : public Funct {
public:
virtual int doit(int x) { ...code from funct3... }
};

Then instead of passing a function-pointer, you pass a Funct*. I'll create a
typedef called FunctPtr merely to make the rest of the code similar to the
old-fashioned approach:

typedef Funct* FunctPtr;

void myCode(FunctPtr f)
{
...
f->doit(...args-go-here...);
...
}

You can create an array of them in almost the same way:

FunctPtr array[10];
array[0] = new Funct1(...ctor-args...);
array[1] = new Funct1(...ctor-args...);
array[2] = new Funct3(...ctor-args...);
array[3] = new Funct2(...ctor-args...);
...

This gives us the first hint about where functionoids are strictly more
powerful than function-pointers: the fact that the functionoid approach has
arguments you can pass to the ctors (shown above as ...ctor-args...) whereas
the function-pointers version does not. Think of a functionoid object as a
freeze-dried function-call (emphasis on the word call). Unlike a pointer to
a function, a functionoid is (conceptually) a pointer to a partially called
function. Imagine for the moment a technology that lets you pass
some-but-not-all arguments to a function, then lets you freeze-dry that
(partially completed) call. Pretend that technology gives you back some sort
of magic pointer to that freeze-dried partially-completed function-call.
Then later you pass the remaining args using that pointer, and the system
magically takes your original args (that were freeze-dried), combines them
with any local variables that the function calculated prior to being
freeze-dried, combines all that with the newly passed args, and continues
the function's execution where it left off when it was freeze-dried. That
might sound like science fiction, but it's conceptually what functionoids
let you do. Plus they let you repeatedly "complete" that freeze-dried
function-call with various different "remaining parameters," as often as you
like. Plus they allow (not require) you to change the freeze-dried state
when it gets called, meaning functionoids can remember information from one
call to the next.

Okay, let's get our feet back on the ground and we'll work a couple of
examples to explain what all that mumbo jumbo really means.

Suppose the original functions (in the old-fashioned function-pointer style)
took slightly different parameters.

int funct1(int x, float y)
{ ...code... }

int funct2(int x, const std::string& y, int z)
{ ...code... }

int funct3(int x, const std::vector<dou ble>& y)
{ ...code... }

When the parameters are different, the old-fashioned function-pointers
approach is difficult to use, since the caller doesn't know which parameters
to pass (the caller merely has a pointer to the function, not the function's
name or, when the parameters are different, the number and types of its
parameters) (do not write me an email about this; yes you can do it, but you
have to stand on your head and do messy things; but do not write me about
it - use functionoids instead).

With functionoids, the situation is, at least sometimes, much better. Since
a functionoid can be thought of as a freeze-dried function call, just take
the un-common args, such as the ones I've called y and/or z, and make them
args to the corresponding ctors. You may also pass the common args (in this
case the int called x) to the ctor, but you don't have to - you have the
option of passing it/them to the pure virtual doit() method instead. I'll
assume you want to pass x and into doit() and y and/or z into the ctors:

class Funct {
public:
virtual int doit(int x) = 0;
};

Then instead of three functions, you create three derived classes:

class Funct1 : public Funct {
public:
Funct1(float y) : y_(y) { }
virtual int doit(int x) { ...code from funct1... }
private:
float y_;
};

class Funct2 : public Funct {
public:
Funct2(const std::string& y, int z) : y_(y), z_(z) { }
virtual int doit(int x) { ...code from funct2... }
private:
std::string y_;
int z_;
};

class Funct3 : public Funct {
public:
Funct3(const std::vector<dou ble>& y) : y_(y) { }
virtual int doit(int x) { ...code from funct3... }
private:
std::vector<dou ble> y_;
};

Now you see that the ctor's parameters get freeze-dried into the functionoid
when you create the array of functionoids:

FunctPtr array[10];

array[0] = new Funct1(3.14f);

array[1] = new Funct1(2.18f);

std::vector<dou ble> bottlesOfBeerOn TheWall;
bottlesOfBeerOn TheWall.push_ba ck(100);
bottlesOfBeerOn TheWall.push_ba ck(99);
...
bottlesOfBeerOn TheWall.push_ba ck(1);
array[2] = new Funct3(bottlesO fBeerOnTheWall) ;

array[3] = new Funct2("my string", 42);

...

So when the user invokes the doit() on one of these functionoids, he
supplies the "remaining" args, and the call conceptually combines the
original args passed to the ctor with those passed into the doit() method:

array[i]->doit(12);

As I've already hinted, one of the benefits of functionoids is that you can
have several instances of, say, Funct1 in your array, and those instances
can have different parameters freeze-dried into them. For example, array[0]
and array[1] are both of type Funct1, but the behavior of array[0]->doit(12)
will be different from the behavior of array[1]->doit(12) since the behavior
will depend on both the 12 that was passed to doit() and the args passed to
the ctors.

Another benefit of functionoids is apparent if we change the example from an
array of functionoids to a local functionoid. To set the stage, let's go
back to the old-fashioned function-pointer approach, and imagine that you're
trying to pass a comparison-function to a sort() or binarySearch() routine.
The sort() or binarySearch() routine is called childRoutine() and the
comparison function-pointer type is called FunctPtr:

void childRoutine(Fu nctPtr f)
{
...
f(...args...);
...
}

Then different callers would pass different function-pointers depending on
what they thought was best:

void myCaller()
{
...
childRoutine(fu nct1);
...
}

void yourCaller()
{
...
childRoutine(fu nct3);
...
}

We can easily translate this example into one using functionoids:

void childRoutine(Fu nct& f)
{
...
f.doit(...args. ..);
...
}

void myCaller()
{
...
Funct1 funct(...ctor-args...);
childRoutine(fu nct);
...
}

void yourCaller()
{
...
Funct3 funct(...ctor-args...);
childRoutine(fu nct);
...
}

Given this example as a backdrop, we can see two benefits of functionoids
over function-pointers. The "ctor args" benefit described above, plus the
fact that functionoids can maintain state between calls in a thread-safe
manner. With plain function-pointers, people normally maintain state between
calls via static data. However static data is not intrinsically
thread-safe - static data is shared between all threads. The functionoid
approach provides you with something that is intrinsically thread-safe since
the code ends up with thread-local data. The implementation is trivial:
change the old-fashioned static datum to an instance data member inside the
functionoid's this object, and poof, the data is not only thread-local, but
it is even safe with recursive calls: each call to yourCaller() will have
its own distinct Funct3 object with its own distinct instance data.

Note that we've gained something without losing anything. If you want
thread-global data, functionoids can give you that too: just change it from
an instance data member inside the functionoid's this object to a static
data member within the functionoid's class, or even to a local-scope static
data. You'd be no better off than with function-pointers, but you wouldn't
be worse off either.

The functionoid approach gives you a third option which is not available
with the old-fashioned approach: the functionoid lets callers decide whether
they want thread-local or thread-global data. They'd be responsible to use
locks in cases where they wanted thread-global data, but at least they'd
have the choice. It's easy:

void callerWithThrea dLocalData()
{
...
Funct1 funct(...ctor-args...);
childRoutine(fu nct);
...
}

void callerWithThrea dGlobalData()
{
...
static Funct1 funct(...ctor-args...); ? the static is the only
difference
childRoutine(fu nct);
...
}

Functionoids don't solve every problem encountered when making flexible
software, but they are strictly more powerful than function-pointers and
they are worth at least evaluating. In fact you can easily prove that
functionoids don't lose any power over function-pointers, since you can
imagine that the old-fashioned approach of function-pointers is equivalent
to having a global(!) functionoid object. Since you can always make a global
functionoid object, you haven't lost any ground. QED.

[ Top | Bottom | Previous section | Next section | Search the FAQ ]


Jul 23 '05 #1
11 4358
* santosh:

I was going through the Marshal Cline's C++ FAQ-Lite.

I have a doubt regarding section 33.10.
That's the one titled "What the heck is a functionoid, and why would I use
one?".

It would have been nice if you had included that title so we could know
what the, uhm, well, you were talking about! :-)

I have a doubt regarding the term "functionoi d"; these small objects are
usually called "functors" in C++, and other things in other languages, and
I haven't encountered the term "functionoi d" anywhere else but in the FAQ.

Here he is declaring a pure virtual destructor in the base class.

And again defining it inline. Like this.

inline Funct::~Funct() { } // defined even though it's pure virtual; it's
faster this way; trust me
There seems to be no reason to declare the destructor in that class as
pure virtual; I don't know why it is (editing blunder?).

My doubt is:

1.. Why we should make destructors pure virtual. What is the advantage?
If you have no other function at hand the destructor is a convenient one
to make pure virtual.

That makes the class effectively abstract at the language level.

It's often done for so-called "marker interfaces".

2.. If it is pure virtual, there should not any definition of it in the
base class. It should be only defined in derived class, so that we can
create the instance of derived class.
No, that is incorrect.

Since the destructor is called there _must_ be a definition of it.

3.. But in this case it is not redefined in derived class. What is the
reason?
The compiler automatically generates a destructor if none is declared.

4.. Again how it is fasted to make it define inline in Base class? Because
inline request will not be obeyed by compiler, if it is virtual.
I think that comment about "faster" (as well as the destructor being pure
virtual) must be an editing blunder, perhaps something from old text about
something else.

I am attaching the 33.10 section of FAQ for your reference.


DON'T DO THAT!

Some people still read news over slow analog lines.

Please do be considerate; give an URL if necessary.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #2
* santosh:
Because
inline request will not be obeyed by compiler, if it is virtual.


Sorry, that is incorrect.

Not that 'inline' is a request that the compiler is bound to obey
anyway.

But the compiler is free to inline calls of a virtual function, and
if it's a good compiler, it will, where appropriate.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #3
> My doubt is:

1.. Why we should make destructors pure virtual. What is the advantage?
Pure virtual functions are used to make classes abstract. One can make
a destructor pure virtual when a class may not have any other candidate
member functions that can be made pure virtual. In such a case, instead
of having a dummy pure virtual function, you can make the destructor
pure virtual.
2.. If it is pure virtual, there should not any definition of it in the
base class. It should be only defined in derived class, so that we can
create the instance of derived class.
Pure virtual destructors _have_ to have a definition. This is because,
in an inheritance heirarchy while destroying a derived class object,
all the destructors in the class heirarchy are called. If you could
leave out the definition of the pure virtual destructor, then there
would be no destructor function body to call.
3.. But in this case it is not redefined in derived class. What is the
reason?
Pure virtual destructors need not be defined in the derived class. The
reason is this. Normal pure virtual functions in a base class would
cause the derived class to be abstract unless it is defined in the
derived class. But destructors are automatically supplied by the
compiler if you don't give one yourself.
4.. Again how it is fasted to make it define inline in Base class? Because
inline request will not be obeyed by compiler, if it is virtual.
I'm not sure about how it would be faster.

Regards,
Srini
santosh wrote: Hello,
I was going through the Marshal Cline's C++ FAQ-Lite.

I have a doubt regarding section 33.10.

Here he is declaring a pure virtual destructor in the base class.

And again defining it inline. Like this.

inline Funct::~Funct() { } // defined even though it's pure virtual; it's
faster this way; trust me

My doubt is:

1.. Why we should make destructors pure virtual. What is the advantage?
2.. If it is pure virtual, there should not any definition of it in the
base class. It should be only defined in derived class, so that we can
create the instance of derived class.
3.. But in this case it is not redefined in derived class. What is the
reason?
4.. Again how it is fasted to make it define inline in Base class? Because
inline request will not be obeyed by compiler, if it is virtual.
I am attaching the 33.10 section of FAQ for your reference.

[33.10] What the heck is a functionoid, and why would I use one?

Functionoids are functions on steroids. Functionoids are strictly more
powerful than functions, and that extra power solves some (not all) of the
challenges typically faced when you use function-pointers.

Let's work an example showing a traditional use of function-pointers, then
we'll translate that example into functionoids. The traditional
function-pointer idea is to have a bunch of compatible functions:

int funct1(...param s...) { ...code... }
int funct2(...param s...) { ...code... }
int funct3(...param s...) { ...code... }

Then you access those by function-pointers:

typedef int(*FunctPtr)( ...params...);

void myCode(FunctPtr f)
{
...
f(...args-go-here...);
...
}

Sometimes people create an array of these function-pointers:

FunctPtr array[10];
array[0] = funct1;
array[1] = funct1;
array[2] = funct3;
array[3] = funct2;
...

In which case they call the function by accessing the array:

array[i](...args-go-here...);

With functionoids, you first create a base class with a pure-virtual method:

class Funct {
public:
virtual int doit(int x) = 0;
virtual ~Funct() = 0;
};

inline Funct::~Funct() { } // defined even though it's pure virtual; it's
faster this way; trust me

Then instead of three functions, you create three derived classes:

class Funct1 : public Funct {
public:
virtual int doit(int x) { ...code from funct1... }
};

class Funct2 : public Funct {
public:
virtual int doit(int x) { ...code from funct2... }
};

class Funct3 : public Funct {
public:
virtual int doit(int x) { ...code from funct3... }
};

Then instead of passing a function-pointer, you pass a Funct*. I'll create a
typedef called FunctPtr merely to make the rest of the code similar to the
old-fashioned approach:

typedef Funct* FunctPtr;

void myCode(FunctPtr f)
{
...
f->doit(...args-go-here...);
...
}

You can create an array of them in almost the same way:

FunctPtr array[10];
array[0] = new Funct1(...ctor-args...);
array[1] = new Funct1(...ctor-args...);
array[2] = new Funct3(...ctor-args...);
array[3] = new Funct2(...ctor-args...);
...

This gives us the first hint about where functionoids are strictly more
powerful than function-pointers: the fact that the functionoid approach has
arguments you can pass to the ctors (shown above as ...ctor-args...) whereas
the function-pointers version does not. Think of a functionoid object as a
freeze-dried function-call (emphasis on the word call). Unlike a pointer to
a function, a functionoid is (conceptually) a pointer to a partially called
function. Imagine for the moment a technology that lets you pass
some-but-not-all arguments to a function, then lets you freeze-dry that
(partially completed) call. Pretend that technology gives you back some sort
of magic pointer to that freeze-dried partially-completed function-call.
Then later you pass the remaining args using that pointer, and the system
magically takes your original args (that were freeze-dried), combines them
with any local variables that the function calculated prior to being
freeze-dried, combines all that with the newly passed args, and continues
the function's execution where it left off when it was freeze-dried. That
might sound like science fiction, but it's conceptually what functionoids
let you do. Plus they let you repeatedly "complete" that freeze-dried
function-call with various different "remaining parameters," as often as you
like. Plus they allow (not require) you to change the freeze-dried state
when it gets called, meaning functionoids can remember information from one
call to the next.

Okay, let's get our feet back on the ground and we'll work a couple of
examples to explain what all that mumbo jumbo really means.

Suppose the original functions (in the old-fashioned function-pointer style)
took slightly different parameters.

int funct1(int x, float y)
{ ...code... }

int funct2(int x, const std::string& y, int z)
{ ...code... }

int funct3(int x, const std::vector<dou ble>& y)
{ ...code... }

When the parameters are different, the old-fashioned function-pointers
approach is difficult to use, since the caller doesn't know which parameters
to pass (the caller merely has a pointer to the function, not the function's
name or, when the parameters are different, the number and types of its
parameters) (do not write me an email about this; yes you can do it, but you
have to stand on your head and do messy things; but do not write me about
it - use functionoids instead).

With functionoids, the situation is, at least sometimes, much better. Since
a functionoid can be thought of as a freeze-dried function call, just take
the un-common args, such as the ones I've called y and/or z, and make them
args to the corresponding ctors. You may also pass the common args (in this
case the int called x) to the ctor, but you don't have to - you have the
option of passing it/them to the pure virtual doit() method instead. I'll
assume you want to pass x and into doit() and y and/or z into the ctors:

class Funct {
public:
virtual int doit(int x) = 0;
};

Then instead of three functions, you create three derived classes:

class Funct1 : public Funct {
public:
Funct1(float y) : y_(y) { }
virtual int doit(int x) { ...code from funct1... }
private:
float y_;
};

class Funct2 : public Funct {
public:
Funct2(const std::string& y, int z) : y_(y), z_(z) { }
virtual int doit(int x) { ...code from funct2... }
private:
std::string y_;
int z_;
};

class Funct3 : public Funct {
public:
Funct3(const std::vector<dou ble>& y) : y_(y) { }
virtual int doit(int x) { ...code from funct3... }
private:
std::vector<dou ble> y_;
};

Now you see that the ctor's parameters get freeze-dried into the functionoid
when you create the array of functionoids:

FunctPtr array[10];

array[0] = new Funct1(3.14f);

array[1] = new Funct1(2.18f);

std::vector<dou ble> bottlesOfBeerOn TheWall;
bottlesOfBeerOn TheWall.push_ba ck(100);
bottlesOfBeerOn TheWall.push_ba ck(99);
...
bottlesOfBeerOn TheWall.push_ba ck(1);
array[2] = new Funct3(bottlesO fBeerOnTheWall) ;

array[3] = new Funct2("my string", 42);

...

So when the user invokes the doit() on one of these functionoids, he
supplies the "remaining" args, and the call conceptually combines the
original args passed to the ctor with those passed into the doit() method:

array[i]->doit(12);

As I've already hinted, one of the benefits of functionoids is that you can
have several instances of, say, Funct1 in your array, and those instances
can have different parameters freeze-dried into them. For example, array[0]
and array[1] are both of type Funct1, but the behavior of array[0]->doit(12)
will be different from the behavior of array[1]->doit(12) since the behavior
will depend on both the 12 that was passed to doit() and the args passed to
the ctors.

Another benefit of functionoids is apparent if we change the example from an
array of functionoids to a local functionoid. To set the stage, let's go
back to the old-fashioned function-pointer approach, and imagine that you're
trying to pass a comparison-function to a sort() or binarySearch() routine.
The sort() or binarySearch() routine is called childRoutine() and the
comparison function-pointer type is called FunctPtr:

void childRoutine(Fu nctPtr f)
{
...
f(...args...);
...
}

Then different callers would pass different function-pointers depending on
what they thought was best:

void myCaller()
{
...
childRoutine(fu nct1);
...
}

void yourCaller()
{
...
childRoutine(fu nct3);
...
}

We can easily translate this example into one using functionoids:

void childRoutine(Fu nct& f)
{
...
f.doit(...args. ..);
...
}

void myCaller()
{
...
Funct1 funct(...ctor-args...);
childRoutine(fu nct);
...
}

void yourCaller()
{
...
Funct3 funct(...ctor-args...);
childRoutine(fu nct);
...
}

Given this example as a backdrop, we can see two benefits of functionoids
over function-pointers. The "ctor args" benefit described above, plus the
fact that functionoids can maintain state between calls in a thread-safe
manner. With plain function-pointers, people normally maintain state between
calls via static data. However static data is not intrinsically
thread-safe - static data is shared between all threads. The functionoid
approach provides you with something that is intrinsically thread-safe since
the code ends up with thread-local data. The implementation is trivial:
change the old-fashioned static datum to an instance data member inside the
functionoid's this object, and poof, the data is not only thread-local, but
it is even safe with recursive calls: each call to yourCaller() will have
its own distinct Funct3 object with its own distinct instance data.

Note that we've gained something without losing anything. If you want
thread-global data, functionoids can give you that too: just change it from
an instance data member inside the functionoid's this object to a static
data member within the functionoid's class, or even to a local-scope static
data. You'd be no better off than with function-pointers, but you wouldn't
be worse off either.

The functionoid approach gives you a third option which is not available
with the old-fashioned approach: the functionoid lets callers decide whether
they want thread-local or thread-global data. They'd be responsible to use
locks in cases where they wanted thread-global data, but at least they'd
have the choice. It's easy:

void callerWithThrea dLocalData()
{
...
Funct1 funct(...ctor-args...);
childRoutine(fu nct);
...
}

void callerWithThrea dGlobalData()
{
...
static Funct1 funct(...ctor-args...); ? the static is the only
difference
childRoutine(fu nct);
...
}

Functionoids don't solve every problem encountered when making flexible
software, but they are strictly more powerful than function-pointers and
they are worth at least evaluating. In fact you can easily prove that
functionoids don't lose any power over function-pointers, since you can
imagine that the old-fashioned approach of function-pointers is equivalent
to having a global(!) functionoid object. Since you can always make a global
functionoid object, you haven't lost any ground. QED.

[ Top | Bottom | Previous section | Next section | Search the FAQ ]


Jul 23 '05 #4
Sam
Srini wrote:
My doubt is:

1.. Why we should make destructors pure virtual. What is the advantage?

Pure virtual functions are used to make classes abstract. One can make
a destructor pure virtual when a class may not have any other candidate
member functions that can be made pure virtual. In such a case, instead
of having a dummy pure virtual function, you can make the destructor
pure virtual.

2.. If it is pure virtual, there should not any definition of it in the
base class. It should be only defined in derived class, so that we can
create the instance of derived class.

Pure virtual destructors _have_ to have a definition. This is because,
in an inheritance heirarchy while destroying a derived class object,
all the destructors in the class heirarchy are called. If you could
leave out the definition of the pure virtual destructor, then there
would be no destructor function body to call.

Correct me if I wrong. The meaning of pure virtual is has no definition
in the base class. Now you said destructor can be pure virtual, but need
to have definition. I m a bit confuse what you said here. If a
function has to have definition, it is not pure virtual.

eg.
virtual ~destructor() = 0;

Do you meant the above example is illegal?

Sam.
3.. But in this case it is not redefined in derived class. What is the
reason?

Pure virtual destructors need not be defined in the derived class. The
reason is this. Normal pure virtual functions in a base class would
cause the derived class to be abstract unless it is defined in the
derived class. But destructors are automatically supplied by the
compiler if you don't give one yourself.

4.. Again how it is fasted to make it define inline in Base class? Because
inline request will not be obeyed by compiler, if it is virtual.

I'm not sure about how it would be faster.

Regards,
Srini

Jul 23 '05 #5
* Sam:

Correct me if I wrong.
OK.
The meaning of pure virtual is has no definition
in the base class.


Wrong.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 23 '05 #6
Sam
Alf P. Steinbach wrote:
* Sam:

Correct me if I wrong.

OK.

The meaning of pure virtual is has no definition
in the base class.

Wrong.

So what is the definition of a pure vritual function in the context of C++?

Jul 23 '05 #7
Sam wrote:
The meaning of pure virtual is has no definition
in the base class.


Wrong.

So what is the definition of a pure vritual function in the context of
C++?


It must be overridden by derived classes.

Jul 23 '05 #8
Sam
Rolf Magnus wrote:
Sam wrote:

The meaning of pure virtual is has no definition
in the base class.

Wrong.


So what is the definition of a pure vritual function in the context of
C++?

It must be overridden by derived classes.

I thought pure virtual means has no definition and derived class must
define its implementation. I remembered you mentioned that the base
class has a vritual keyword on the ~desutrctor, but with definition or
implementation for the pure virtual destructor.

Sam
Jul 23 '05 #9
Sam wrote:
Rolf Magnus wrote:
Sam wrote:

> The meaning of pure virtual is has no definition
> in the base class.
Wrong.
So what is the definition of a pure vritual function in the context of
C++?
It must be overridden by derived classes.

I thought pure virtual means has no definition and derived class must
define its implementation.


Both are wrong.
I remembered you mentioned that the base
class has a vritual keyword on the ~desutrctor, but with definition or
implementation for the pure virtual destructor.


There is no connection between "pure" and "has no definition" except that
you _may_ omit a definition of a pure virtual function *unless* it is
the destructor. And in most cases, that's what people do, they declare
virtual functions as pure because there is nothing that can represent the
behaviour of the object of that class when that function is called -- the
behaviour will be provided by the derived classes, and only those that do
actually have it.

Now, as to "must define": only the _concrete_ class has to have all its
virtual functions defined. It stems from the definition of the concrete
class. IOW, if I have a class that derives from an abstract class *and*
does *not* define some of the pure virtual functions, my derived class
is simply abstract, just like the one it derives from.

V
Jul 23 '05 #10

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

Similar topics

37
4166
by: WittyGuy | last post by:
Hi, I wonder the necessity of constructor and destructor in a Abstract Class? Is it really needed? ? Wg http://www.gotw.ca/resources/clcm.htm for info about ]
6
3488
by: pakis | last post by:
I am having a problem of pure virtual function call in my project. Can anyone explaine me the causes of pure virtual function calls other than calling a virtual function in base class? Thanks
21
2564
by: sks | last post by:
Hi , could anyone explain me why definition to a pure virtual function is allowed ?
4
1868
by: Eric | last post by:
I was wondering what people thought about the information found at: http://g.oswego.edu/dl/mood/C++AsIDL.html Specifically, I am interested in the following recommendation: ---- Since interface classes cannot be directly instantiated, yet serve as virtual base classes for implementations, the constructors should take no arguments and should be listed as protected. Also, for similar
4
411
by: =?utf-8?Q?David_C=C3=B4me?= | last post by:
Hello everybody. I have a question. When i want use a pure virtual destructor in one of my classe, i must give a definition of this destructor like this: class A { //a lot of things virtual ~A() =0; };
2
4083
by: manjuks | last post by:
Hi, I have defined pure virtual destructor in base class. As far as I know pure virtual function makes us to redefine the same function in derived classes also. and also we can not create a objects of class which contains pure virtual functions but we can create pointer or reference of the same. My problem is I have defined a pure virtual function in base class, so I have to redefine the same in derived class. When I did the same...
7
3694
by: arnaudk | last post by:
How come it's possible to have a base class with a pure virtual destructor and nonetheless one has to implement the destructor? Doesn't pure virtual mean that there is no implementation of that method in the base class and the implementation is left entirely up to derived classes? class Base { public: Base() {} virtual ~Base() = 0; // pure virtual destructor } Base::~Base() // <-- Linktime error if {} // this...
14
2749
by: Jack | last post by:
Hi, I meet a question with it , I did not get clear the different betteen them, for example: #include <iostream>
7
7361
by: Tonni Tielens | last post by:
I'm trying to create a pure virtual class describing an interface. Normally, when I do this I make the destructor pure virtual so that, even if there are no members in the class, it cannot be instantiated. The difference now is that I'm making a generic interface with template arguments. Template classes should be defined in the header file, but it is not allowed for a destructor's definition to be in the class definition if the...
0
8759
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
8669
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
9122
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9017
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
7872
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
6588
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 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 a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5922
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
4433
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
3
2069
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

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.