Override virtual member functions in Subclasses

  • Thread starter Ruben Van Havermaet
  • Start date
R

Ruben Van Havermaet

Hi,

I have a problem using member functions in derived classes that
override virtual member functions of base classes.

The following pieces of (simplified) code don't work. Can anybody give
me some hints on what might be wrong?

// BEGIN OF SAMPLE CODE
class Strategy
{
public:
Strategy() {}
virtual void run() { cout<<"Please override!"; }
};

class StrategyA: public Strategy
{
public:
StrategyA() {}
void run();
};
void StategyA::run()
{
cout <<"Functionality A";
}


class SomeClass
{
public:
SomeClass(Strategy s);

void doSomething();

private:
Strategy s_;
};

SomeClass::SomeClass(Strategy s): s_(s) {}

SomeClass::doSomething()
{
s_.run();
}


int main()
{
StategyA s;
SomeClass c(s);

c.doSomething();

return 0;
}
// END OF SAMPLE CODE


The above program will print out "Please override!" instead of
"Functionality A". Scanning through Stroustrup I can't seem to find
what is wrong.

An additional remark: I know it is better to declare the function
"run" in Strategy to be pure virtual (virtual void run() = 0;) but
that won't compile. The compiler gives error in SomeClass' constructor
and private member declaration. What do I forget?

Thanks In Advance,

With Kind Regards

Ruben Van Havermaet.
 
S

Stephen Tyndall

Ruben Van Havermaet said:
Hi,

I have a problem using member functions in derived classes that
override virtual member functions of base classes.

The following pieces of (simplified) code don't work. Can anybody give
me some hints on what might be wrong?

// BEGIN OF SAMPLE CODE

You know this, but I'm going to go ahead and put it here:

class Strategy
{
public:
Strategy() {}
virtual void run() { cout<<"Please override!"; }
};

class StrategyA: public Strategy
{
public:
StrategyA() {}
void run();

Style: the run() function above is virtual; it's best to go ahead and say
"virtual" to remind you what it is.
};
void StategyA::run()

void StrategyA::run()
{
cout <<"Functionality A";
}


class SomeClass
{
public:
SomeClass(Strategy s);

Style: constructors and destructors are inline no matter what you do, so
it's usually best just to put the constructor/destructor definitions inside
the class like this:

SomeClass(Strategy s) : s_(s) { }

Also, initializing a data member like this has no effect. The private
member variable Strategy s_ is already a Strategy. "Initializing" it with a
StrategyA has no effect. There is no data that needs to be initialized, and
you can't initialize a object with another object anyway.

Change your constructor to:

SomeClass() { }
void doSomething();

private:
Strategy s_;

SomeClass' data member is a Strategy, not a StrategyA. If you changed this
to

StrategyA s_;

Then it will work.
};

SomeClass::SomeClass(Strategy s): s_(s) {}

Erase the line above.
SomeClass::doSomething()

void SomeClass::doSomething()

If you don't supply a return type, int is assumed. Since this function
returns no value, void is required.
{
s_.run();
}


int main()
{
StategyA s;

This should be

StrategyA s;

except that it shouldn't be there.
SomeClass c(s);

Change this to

SomeClass c;

After all these changes, the program should work.
c.doSomething();

This will print "Functionality A" now.
return 0;
}
// END OF SAMPLE CODE


The above program will print out "Please override!" instead of
"Functionality A". Scanning through Stroustrup I can't seem to find
what is wrong.

An additional remark: I know it is better to declare the function
"run" in Strategy to be pure virtual (virtual void run() = 0;) but
that won't compile. The compiler gives error in SomeClass' constructor
and private member declaration. What do I forget?

Declaring a pure virtual function makes the class an ADT (abstract data
type). Because you cannot create an object of an ADT, it must have a
default constructor (but that's already there). The problem comes from
trying to give SomeClass a Strategy member. When you do this, a Strategy
object is "constructed" inside SomeClass, which is an error. The SomeClass
constructor error is basically the same; it comes from trying to initialize
an object of the Strategy ADT.

Here's my version of your code. It should have everything working.

#include <iostream>

using std::cout;

class Strategy

{

public:

Strategy() {}

virtual void run() { cout<<"Please override!"; }

};

class StrategyA: public Strategy

{

public:

StrategyA() {}

virtual void run();

};

void StrategyA::run()

{

cout <<"Functionality A\n";

}



class SomeClass

{

public:

SomeClass() { }

void doSomething();

private:

StrategyA s_;

};

void SomeClass::doSomething()

{

s_.run();

}

int main()

{

SomeClass c;

c.doSomething();

return 0;

}



//good luck!

//mike tyndall
 
J

JKop

Stephen Tyndall posted:
If you don't supply a return type, int is assumed. Since this function
returns no value, void is required.


Incorrect.

There are three and only three instances in which you may not specify a
return type (and in all three instances it is compulsory that you don't):

a) Constructors

b) Destructor

c) Type conversion operators


class Blah
{
public:

Blah();

~Blah();

operator int();
};


-JKop
 
V

Victor Bazarov

Stephen said:
Style: constructors and destructors are inline no matter what you do, so

Where did you get this nonsense?
it's usually best just to put the constructor/destructor definitions inside
the class like this:

SomeClass(Strategy s) : s_(s) { }

Also, initializing a data member like this has no effect.

What are you talking about?
The private
member variable Strategy s_ is already a Strategy. "Initializing" it with a
StrategyA has no effect.

Are you out of your mind?
There is no data that needs to be initialized, and

What if I later add data to be initialised?
you can't initialize a object with another object anyway.
What????


Change your constructor to:
[...]

I removed the rest of your nonsense. Please read up on polymorphism
before attempting to advise unsuspecting newbies.

V
 
V

Victor Bazarov

Ruben said:
I have a problem using member functions in derived classes that
override virtual member functions of base classes.

The following pieces of (simplified) code don't work. Can anybody give
me some hints on what might be wrong?

What is wrong is that you are trying to achieve polymorphic behaviour
without using pointers or references. That's rather impossible.
// BEGIN OF SAMPLE CODE
class Strategy
{
public:
Strategy() {}
virtual void run() { cout<<"Please override!"; }
};

class StrategyA: public Strategy
{
public:
StrategyA() {}
void run();
};
void StategyA::run()
{
cout <<"Functionality A";
}


class SomeClass
{
public:
SomeClass(Strategy s);

Change this to

SomeClass(Strategy& rs);
void doSomething();

private:
Strategy s_;

Change this to

Strategy& s_;
};

SomeClass::SomeClass(Strategy s): s_(s) {}

And this to

SomeClass::SomeClass(Strategy& s): s_(s) {}
SomeClass::doSomething()
{
s_.run();
}


int main()
{
StategyA s;
SomeClass c(s);

c.doSomething();

return 0;
}
// END OF SAMPLE CODE

Now it should work as expected.

Victor
 
S

Stephen Tyndall

JKop said:
Stephen Tyndall posted:


Incorrect.

There are three and only three instances in which you may not specify a
return type (and in all three instances it is compulsory that you don't):

a) Constructors

b) Destructor

c) Type conversion operators


class Blah
{
public:

Blah();

~Blah();

operator int();
};

This came from VC++.NET; when I moved his code into it and tried to compile,
it complained that the "function (name) differs from (name) only by return
type." He had declared it as void, and the output window said that the
function definition had an int return type. Another VC++ slipup?

//mike tyndall
 
A

Ali Cehreli

This came from VC++.NET; when I moved his code into it and tried to
compile, it complained that the "function (name) differs from (name)
only by return type." He had declared it as void, and the output window
said that the function definition had an int return type. Another VC++
slipup?

It must be a backward compatibility extension of the compiler. In the
old old days of C we could leave out the return type of functions and
the return type would be 'int'. Not in the later standard C; certainly
not in C++...

Ali
 
S

Stephen Tyndall

Victor Bazarov said:
Where did you get this nonsense?

Actually, I don't know. Reading my post again, there's some stuff there
that's really stupid, and I don't understand why it was even there. I had
just gotten out of bed (I know, ridiculously late), so I really should have
given it some more time before I posted. I just wasn't thinking
clearly...obviously a constructor is called when an object is created, but
it's never inline.
What are you talking about?

You're thinking I said that the initialization list didn't initialize
anything, and it's true I could have been more clear. I meant to say that
the class object data member couldn't be initialized like this because
there's no data inside the object to be initialized.
Are you out of your mind?

True, the StrategyA object could hold data to initialize the Strategy
object. But this wasn't what he was doing.
What if I later add data to be initialised?

We're not talking about you here. We're talking about his code; he didn't
have any data to initialize.

Crap, that was stupid. Why was that there? All through the post, I see
places where I used general terms instead of saying it only applied to his
code.

//apologetically,
//mike tyndall
 
S

Stephen Tyndall

Ali Cehreli said:
It must be a backward compatibility extension of the compiler. In the
old old days of C we could leave out the return type of functions and
the return type would be 'int'. Not in the later standard C; certainly
not in C++...

Any idea how I would turn that off?

//mike tyndall
 
J

John Harrison

Any idea how I would turn that off?

//mike tyndall

I would try 'disable language extensions'. I'd don't know if it works in
this case but its certainly worth having on. Along with other beauties
like 'treat wchar_t as built in type', 'force conformance in for loop
scope', and 'enable run time type info'. With all those you'll have a
reasonably standard conformant compiler. And make sure you've upgraded to
7.1

john
 
S

Stephen Tyndall

John Harrison said:
I would try 'disable language extensions'. I'd don't know if it works in
this case but its certainly worth having on. Along with other beauties
like 'treat wchar_t as built in type', 'force conformance in for loop
scope', and 'enable run time type info'. With all those you'll have a
reasonably standard conformant compiler. And make sure you've upgraded to
7.1

Thanks. I switched all of those on.

//mike tyndall
 
R

red floyd

John said:
I would try 'disable language extensions'. I'd don't know if it works
in this case but its certainly worth having on. Along with other
beauties like 'treat wchar_t as built in type', 'force conformance in
for loop scope', and 'enable run time type info'. With all those you'll
have a reasonably standard conformant compiler. And make sure you've
upgraded to 7.1

john

Does the Holy Standard specify wchar_t as a builtin?
Also, for those who must include <windows.h> (ugh!), disabling language
extensions is not an option.

My second sentence is waaaay OT, so I'll stop here.
 
J

John Harrison

Does the Holy Standard specify wchar_t as a builtin?

Yes it does, its a type in it own right, but Visual C++ compilers treat it
as a typedef (for unsigned short I think).

john
 
R

Rolf Magnus

Stephen said:
You know this, but I'm going to go ahead and put it here:



Style: the run() function above is virtual; it's best to go ahead and
say "virtual" to remind you what it is.


void StrategyA::run()


Style: constructors and destructors are inline no matter what you do,

Huh? Who told you that? It's wrong.
so it's usually best just to put the constructor/destructor
definitions inside the class like this:

SomeClass(Strategy s) : s_(s) { }

It's as good or bad as putting any member function directly into the
class definition.
Also, initializing a data member like this has no effect. The private
member variable Strategy s_ is already a Strategy. "Initializing" it
with a StrategyA has no effect.

Well, there is an effect, but not the desired one.
There is no data that needs to be initialized, and you can't
initialize a object with another object anyway.

Yes, you can.
Change your constructor to:

SomeClass() { }

The above line is useless. You can just leave the whole constructor out
instead. The compiler will automatically generate the above one.
SomeClass' data member is a Strategy, not a StrategyA. If you changed
this to

StrategyA s_;

Then it will work.

That however won't bring the OP any closer to polymorphic behaviour.
Erase the line above.


void SomeClass::doSomething()

If you don't supply a return type, int is assumed. Since this
function returns no value, void is required.


This should be

StrategyA s;

except that it shouldn't be there.


Change this to

SomeClass c;

After all these changes, the program should work.

That depends on your definition of "should work". It might compile and
do something, but for sure not what was intended.
This will print "Functionality A" now.


Declaring a pure virtual function makes the class an ADT (abstract
data type). Because you cannot create an object of an ADT, it must
have a default constructor (but that's already there).
Nonsense.

The problem comes from trying to give SomeClass a Strategy member.
When you do this, a Strategy object is "constructed" inside SomeClass,
which is an error.

Right. The class cannot be instantiated, because it's abstract.
 
S

Stephen Tyndall

Rolf Magnus said:
Huh? Who told you that? It's wrong.

Yeah, I know. I don't know what I was thinking. I originally thought that
"inline function" meant "function not explicitly called by the programmer"
(like a constructor/destructor, or sort of like an operator) and was kind of
confused for a while. That's been cured now, but I apparently had a relapse
: )
Well, there is an effect, but not the desired one.


Yes, you can.


The above line is useless. You can just leave the whole constructor out
instead. The compiler will automatically generate the above one.

Yeah, I know. I tend to go ahead and put it there in my code anyway, even
though it's pointless.
Nonsense.

What do you mean? My beginner's book a while back made it clear several
times that having a pure virtual function makes a class an ADT. Do you mean
the thing about the constructor?

BTW, Victor Bazarov caught some other mistakes in my post that you may or
may not have seen. I was very groggy this morning : )

//mike tyndall
 
D

David Hilsee

What do you mean? My beginner's book a while back made it clear several
times that having a pure virtual function makes a class an ADT. Do you mean
the thing about the constructor?

I must admit, that constructor comment does sound like nonsense. To me, it
makes about as much sense as saying that the class must be named Fred. You
were quite groggy, weren't you? ;-)
 
S

Stephen Tyndall

David Hilsee said:
I must admit, that constructor comment does sound like nonsense. To me, it
makes about as much sense as saying that the class must be named Fred. You
were quite groggy, weren't you? ;-)

Heh :)
Don't worry, next time I'll take the time to go over my post a few times
(and maybe use the word "time" a little less).

//mike tyndall
 
P

pankaj tiwary

Victor Bazarov said:
What is wrong is that you are trying to achieve polymorphic behaviour
without using pointers or references. That's rather impossible.
I quite agree with what Victor says. The problem is just becasue the
op is trying to get the polymorphic behaviour. I tried the same code
with pointers(references would create problem for this particular
code) and I found the code is running perfectly fine.

#include <iostream>

using namespace std ;

class Base {
public:
Strategy() {}
virtual void run() { cout<<"Please override!"<<endl; }
} ;

class Derived : public Base {
public:
Derived() {}
virtual void run() { cout <<"Functionality A"<<endl; };
} ;

class Someclass {
private:
Base* b_ ;
public:
Someclass(Base* b) : b_(b){ }
void doSomething() { b_->run(); }
} ;

int main() {
Base* a = new Base();
Derived* d = new Derived();
Someclass s(a) ;
Someclass s1(d);
s.doSomething() ;
s1.doSomething() ;
return 0 ;
}
------------------------------------------
output:
Please override!
Functionality A
------------------------------------------
I think this is what op wanted to clarify.

pls point out , if I am wrong somewhere.

pankaj
 
R

Ruben Van Havermaet

Victor Bazarov said:
What is wrong is that you are trying to achieve polymorphic behaviour
without using pointers or references. That's rather impossible.

I guess that forgetting to mention the word 'polymorphism' made my
post somewhat inclear. :)

Thanks, Victor, I got it working now. If you're used to dynamically
typed languages, c++ turns out to be quite a challenge :)


Declaring the Strategy class to be abstract now also works. I assume
that this is because

Strategy& strat

in the private member declaration of SomeClass, doesn't need to be
constructed.



Friendly Greetings
Ruben.
 

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

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top