Why can't I do this?

Q

Quentin

Dear Gurus,

This is a fairly simple question, but I can't figure out what the answer is.
I can easily change my code, but I want to know why I can't do this to
further my knowledge of the C++ language (and OO):

class a
{
public:
a(){ vm(); }
virtual void vm() = 0;
};

class b : public a
{
public:
void vm() { }
};

int main()
{
b B;

return 0;
}

VC++ says: "error LNK2001: unresolved external symbol "public: virtual void
__thiscall a::vm(void)"

I understand that 'a' doesn't have a implementation of 'vm', but also I
cannot create an instance of 'a' either (because it has a pure virtual
function) so when I create a 'b' why can't 'a's constructor call 'b's 'vm'?

Quentin.
 
A

Alf P. Steinbach

This is a fairly simple question, but I can't figure out what the answer is.
I can easily change my code, but I want to know why I can't do this to
further my knowledge of the C++ language (and OO):

class a
{
public:
a(){ vm(); }
virtual void vm() = 0;
};

class b : public a
{
public:
void vm() { }
};

int main()
{
b B;

return 0;
}

VC++ says: "error LNK2001: unresolved external symbol "public: virtual void
__thiscall a::vm(void)"

I understand that 'a' doesn't have a implementation of 'vm', but also I
cannot create an instance of 'a' either (because it has a pure virtual
function) so when I create a 'b' why can't 'a's constructor call 'b's 'vm'?

This is a FAQ.

Look it up in the FAQ.

If necessary, first look up where the FAQ is (Google, this group).


Hth.,

- Alf
 
M

Marcin Vorbrodt

Quentin said:
Dear Gurus,

This is a fairly simple question, but I can't figure out what the answer is.
I can easily change my code, but I want to know why I can't do this to
further my knowledge of the C++ language (and OO):

class a
{
public:
a(){ vm(); }
virtual void vm() = 0;
};

class b : public a
{
public:
void vm() { }
};

int main()
{
b B;

return 0;
}

VC++ says: "error LNK2001: unresolved external symbol "public: virtual void
__thiscall a::vm(void)"

I understand that 'a' doesn't have a implementation of 'vm', but also I
cannot create an instance of 'a' either (because it has a pure virtual
function) so when I create a 'b' why can't 'a's constructor call 'b's 'vm'?

Quentin.

Because at the time of construction of A part "this" pointer is still of
type A, hence it does not know anything about B yet. In other words,
construction starts at the top of inheritance tree, and the type of this
pointer follows. BTW, Mayers in his book Effectife C++ has a chapter about
this... you shouldn't (in most cases) call virtual functions from
constructors.

Martin
 
B

Bill Thompson

Quentin said:
Dear Gurus,

This is a fairly simple question, but I can't figure out what the answer is.
I can easily change my code, but I want to know why I can't do this to
further my knowledge of the C++ language (and OO):

class a
{
public:
a(){ vm(); }
virtual void vm() = 0;
};

class b : public a
{
public:
void vm() { }
};

int main()
{
b B;

return 0;
}

VC++ says: "error LNK2001: unresolved external symbol "public: virtual void
__thiscall a::vm(void)"

I understand that 'a' doesn't have a implementation of 'vm', but also I
cannot create an instance of 'a' either (because it has a pure virtual
function) so when I create a 'b' why can't 'a's constructor call 'b's 'vm'?

Quentin.
I'm by no means a guru, and of course you can check the FAQ, but I believe
this is the problem:
Class A is an abstract base class containing an unimplemented virtual
function. Therefore, you cannot call vm() from the Class A constructor,
because in Class A it doesn't exist.

Call vm() from Class B's constructor.

Think about it... why should the compiler allow you to call Class A's vm()
if it has no function body? The compiler is doing you a favor here.

An additional question: were you to derive additional classes from A, how
would the compiler know which instance of vm() to call in A's constructor?
 
J

jeffc

Quentin said:
Dear Gurus,

This is a fairly simple question, but I can't figure out what the answer is.
I can easily change my code, but I want to know why I can't do this to
further my knowledge of the C++ language (and OO):

class a
{
public:
a(){ vm(); }
virtual void vm() = 0;
};

class b : public a
{
public:
void vm() { }
};

int main()
{
b B;

return 0;
}

VC++ says: "error LNK2001: unresolved external symbol "public: virtual void
__thiscall a::vm(void)"

I understand that 'a' doesn't have a implementation of 'vm', but also I
cannot create an instance of 'a' either (because it has a pure virtual
function) so when I create a 'b' why can't 'a's constructor call 'b's
'vm'?

Whoa dude, you had it there for a minute. Now step back and think about
what you're saying. Why would a base class EVER need to know anything about
any of its subclasses? Inheritance doesn't work that way. When you create
a b, b's constructor gets called, which means a's constructor is going to
get called. But a base class function shouldn't call a subclass function.
Once you're in code for a, all it sees is a.

By the way, just because a is abstract doesn't mean you can't give a
definition for the pure virtual function. It's a common mistake to think
that though. It's often a useful technique to make a function pure virtual,
but then provide a definition that the base classes can call from their
overridden function, to do at least some common work. It might even be all
that some subclasses need to do.
 
J

jeffc

jeffc said:
Whoa dude, you had it there for a minute. Now step back and think about
what you're saying. Why would a base class EVER need to know anything about
any of its subclasses? Inheritance doesn't work that way. When you create
a b, b's constructor gets called, which means a's constructor is going to
get called. But a base class function shouldn't call a subclass function.

I was talking only about the constructor in this case, of course, not the
general case of function overriding. Constructor time is different.
 
Q

Quentin

Whoa dude, you had it there for a minute. Now step back and think about
what you're saying. Why would a base class EVER need to know anything about
any of its subclasses? Inheritance doesn't work that way. When you create
a b, b's constructor gets called, which means a's constructor is going to
get called. But a base class function shouldn't call a subclass function.
Once you're in code for a, all it sees is a.

I get it now. Whoa dude :) hahaha!
By the way, just because a is abstract doesn't mean you can't give a
definition for the pure virtual function. It's a common mistake to think
that though. It's often a useful technique to make a function pure virtual,
but then provide a definition that the base classes can call from their
overridden function, to do at least some common work. It might even be all
that some subclasses need to do.

Whoa dude, I did not know that! That could be very useful. Thanks for the
tip!

Quentin.
 
M

Marcelo Pinto

Bill Thompson said:
I'm by no means a guru, and of course you can check the FAQ, but I believe
this is the problem:
Class A is an abstract base class containing an unimplemented virtual
function. Therefore, you cannot call vm() from the Class A constructor,
because in Class A it doesn't exist.

Call vm() from Class B's constructor.

Think about it... why should the compiler allow you to call Class A's vm()
if it has no function body? The compiler is doing you a favor here.

An additional question: were you to derive additional classes from A, how
would the compiler know which instance of vm() to call in A's constructor?

Note that this is only true for calls in constructors. It's perfectly
valid to call an abstract function from any function except from
constructors and destructors (?).

BTW it is the central idea in the Template Method Pattern.

Regards,

Marcelo Pinto
 
B

Bill Thompson

Marcelo Pinto said:
"Bill Thompson" <[email protected]> wrote in message constructor?

Note that this is only true for calls in constructors. It's perfectly
valid to call an abstract function from any function except from
constructors and destructors (?).

BTW it is the central idea in the Template Method Pattern.

Regards,

Marcelo Pinto

Yes, of course, after construction the vtable has been initialized. I
should have made it more obvious I was referring to constructors, not
calling virtual functions in general.
 
J

jeffc

Quentin said:
Whoa dude, I did not know that! That could be very useful. Thanks for the
tip!

I had a typo - I meant "provide a definition that the *subclasses* can call
from their overridden function".

Example. Program for a football game. You have football players.

class FootballPlayer
class Punter : public FootballPlayer
class DefensiveEnd : public FootballPlayer

You don't have any players on the field that are so generic that you'd
create a FootballPlayer - everyone plays a specific position. Therefore,
you make FootballPlayer abstract. But in case of crazy plays, you want
every player on the field to be able to make a tackle. You might have a
pure virtual function called Tackle() which provides some basic tackling
technique.

class FootballPlayer
{
public:
void Tackle() = 0;
};

You might override Tackle() if there is some special technique defensive
players might use. But there's nothing wrong with defining
void FootballPlayer::Tackle()
{
// tackle in some basic way
}

Then Punter could just do
void Punter::Tackle()
{
FootballPlayer::Tackle(); // the basic base function is good enough
}

The DefensiveEnd might add
void DefensiveEnd::Tackle()
{
FootballPlayer::Tackle();
// plus add a harder hit, or trying to punch the ball away on the way down
}
 
C

Christopher Benson-Manica

jeffc said:
You don't have any players on the field that are so generic that you'd
create a FootballPlayer - everyone plays a specific position. Therefore,
you make FootballPlayer abstract. But in case of crazy plays, you want
every player on the field to be able to make a tackle. You might have a
pure virtual function called Tackle() which provides some basic tackling
technique.
class FootballPlayer
{
public:
void Tackle() = 0;
};
You might override Tackle() if there is some special technique defensive
players might use. But there's nothing wrong with defining
void FootballPlayer::Tackle()
{
// tackle in some basic way
}
Then Punter could just do
void Punter::Tackle()
{
FootballPlayer::Tackle(); // the basic base function is good enough
}

Like football eh? ;) Seriously, I'm still a C++ newb, so I'm not seeing the
point of defining a pure virtual function and then overriding it. Why not
just make it a regular virtual function?
 
R

Ron Natalie

Christopher Benson-Manica said:
Like football eh? ;) Seriously, I'm still a C++ newb, so I'm not seeing the
point of defining a pure virtual function and then overriding it. Why not
just make it a regular virtual function?
Why use function overloading, just give everything seperate names?
Because it makes sense to have the base class behavior impelemented
in a function of the same name, even if you're forced to think about
whether that is the proper behavior (by itself) in a derived class.
 
C

Christopher Benson-Manica

Ron Natalie said:
Why use function overloading, just give everything seperate names?
Because it makes sense to have the base class behavior impelemented
in a function of the same name, even if you're forced to think about
whether that is the proper behavior (by itself) in a derived class.

M... (denseness/cluelessness alert!)

I thought the point of a pure virtual function was to force subclasses to
implement it, since the base class explicitly declines to do so. If the base
class wants to provide an implementation of a member function, what is
accomplished by declaring it to be purely virtual? Is it so a class that uses
classes derived from the base can choose to override the base virtual
function......?
 
R

Ron Natalie

Christopher Benson-Manica said:
M... (denseness/cluelessness alert!)

I thought the point of a pure virtual function was to force subclasses to
implement it, since the base class explicitly declines to do so.

The first part of your statement is true, the second isn't. It forces the
derived classes (at least those who are going to be concrete) to provide
an implementation, but it doesn't say boo about whether the base class
does or not.
If the base
class wants to provide an implementation of a member function, what is
accomplished by declaring it to be purely virtual?

We just told you, and the football example was provided. I'll give you a more real
world one right out of our main product. Inside we have a bunch of objects that
get passed around generically. They have various functions they implement
(including such common things as the relational operators, serialize output, etc...).
Lets take the serialize function. There is a default behavior of just writing an
encoded version of the object type (which there is obtainable from the base class
via another virtual function). However, that's NOT good enough for many of
the objects. Therefore, I make the base class method pure, so that it MUST
be overridden. This forces the derived class writer to make the decision between
using the default behavior or writing a different implementation. What it doesn't
allow (and we were screwed by this a couple of times before we did this) is
to forget to put an explicit statement of the proper behavior in his class definition.

Is it so a class that uses
classes derived from the base can choose to override the base virtual
function......?

Well a class can always chose to override the function. What it does is force
the derived class to make an explicit statement as to whether he wants the
base behavior or something else.
 

Ask a Question

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

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

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,142
Messages
2,570,819
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top