derived class and virtual function

S

subramanian100in

In Stanley Lippman's 'C++ Primer Fourth Edition', in page 564, the
following is mentioned:

"A virtual function in the derived class can return a reference or
pointer to a class that is PUBLICLY derived from the type returned by
the base class function."

I am unable to understand this sentence. Kindly explain it with
program sample.

Thanks
V.Subramanian
 
F

Francesco S. Carta

on said:
In Stanley Lippman's 'C++ Primer Fourth Edition', in page 564, the
following is mentioned:

"A virtual function in the derived class can return a reference or
pointer to a class that is PUBLICLY derived from the type returned by
the base class function."

I am unable to understand this sentence. Kindly explain it with
program sample.

IIUIC, that means that if you have a function with signature "virtual
Base* Clone() const;" in the base class, then the implementation of the
same function in the derived class can be: "Base* Clone() const { return
new Derived(*this); }" - just an example that assumes Derived is
copy-constructible, of course.
 
S

Stefan van Kessel

In Stanley Lippman's 'C++ Primer Fourth Edition', in page 564, the
following is mentioned:

"A virtual function in the derived class can return a reference or
pointer to a class that is PUBLICLY derived from the type returned by
the base class function."

I am unable to understand this sentence. Kindly explain it with
program sample.

Thanks
V.Subramanian

It allows you for example to write code like this (polymorphic copy)

#include <iostream>
class Foo
{
public:
virtual Foo* createCopy(){ return new Foo(*this); }
virtual void quack() { std::cout<<"I'm a foo"<<std::endl; }
virtual ~Foo(){}
};

class Bar : public Foo
{
public:
// notice that this createCopy returns a Bar* instead of Foo*
// which is a "pointer to a class that is PUBLICLY derived"
virtual Bar* createCopy(){ return new Bar(*this); }
virtual void quack() { std::cout<<"I'm a bar"<<std::endl; }
};

int main() {
Bar bar;
Foo& br = bar;
Foo* bp = br.createCopy();
bp->quack();
delete bp;
}
 
F

Francesco S. Carta

IIUIC, that means that if you have a function with signature "virtual
Base* Clone() const;" in the base class, then the implementation of the
same function in the derived class can be: "Base* Clone() const { return
new Derived(*this); }" - just an example that assumes Derived is
copy-constructible, of course.

There is either something wrong in that sentence, in my understanding
or in my compiler - or my settings thereof - because it allows me to
return a pointer to Derived where Base is private:

//-------

#include <iostream>

using namespace std;

class Base {
public:
Base(int data = 0) : data(data) {};
Base(const Base& base) : data(base.data) {};
virtual Base* Clone() const {
cout << "cloning Base" << endl;
return new Base(*this);
}
int Data() const {
return data;
}
private:
int data;
};

class Derived : private Base {
public:
Derived(int data = 0) : Base(data) {};
Derived(const Derived& derived) : Base(derived) {};
Base* Clone() const {
cout << "cloning Derived" << endl;
return new Derived(*this);
}
};

int main() {

// fails, of course
// Base* pb = new Derived(42);

Derived d(42);

// calls Derived::Clone()
Base* pb2 = d.Clone();

// calls Derived::Clone()
Base* pb3 = pb2->Clone();

// prints 42
cout << pb3->Data() << endl;
}

//-------
 
F

Francesco S. Carta

on 13/08/2010 10:51:30 said:
It allows you for example to write code like this (polymorphic copy)

#include <iostream>
class Foo
{
public:
virtual Foo* createCopy(){ return new Foo(*this); }
virtual void quack() { std::cout<<"I'm a foo"<<std::endl; }
virtual ~Foo(){}
};

class Bar : public Foo
{
public:
// notice that this createCopy returns a Bar* instead of Foo*
// which is a "pointer to a class that is PUBLICLY derived"
virtual Bar* createCopy(){ return new Bar(*this); }
virtual void quack() { std::cout<<"I'm a bar"<<std::endl; }
};

int main() {
Bar bar;
Foo& br = bar;
Foo* bp = br.createCopy();
bp->quack();
delete bp;
}

Ah, this makes more sense than my example, but I've been able to make it
work even declaring Bar::createCopy() as non-virtual, just for the records.
 
S

Stuart Redmann

Ah, this makes more sense than my example, but I've been able to make it
work even declaring Bar::createCopy() as non-virtual, just for the records.

A question pops up: How exactly did you manage to make Bar::createCopy
non-virtual? AFAIK, C++ does not allow this.

Regards,
Stuart
 
F

Francesco S. Carta

A question pops up: How exactly did you manage to make Bar::createCopy
non-virtual? AFAIK, C++ does not allow this.

I've just copied Stefan's code, pasted it into my editor, deleted the
two "virtual" from createCopy() and quack() within class Bar and
compiled it with MinGW 4.4.0.

The output was: "I'm a bar".

Notice that I wrote "declaring Bar::createCopy() as non-virtual", as far
as I know I did not "make Bar::createCopy non-virtual" as you said.
 
I

Ian Collins

I've just copied Stefan's code, pasted it into my editor, deleted the
two "virtual" from createCopy() and quack() within class Bar and
compiled it with MinGW 4.4.0.

So the function are still virtual. The virtual keyword in the derived
class is superfluous.
 
F

Francesco S. Carta

So the function are still virtual. The virtual keyword in the derived
class is superfluous.

That's what I meant to say with "declaring Bar::createCopy() as
non-virtual". I guess the keyword is still needed if I want to further
redefine that function in a further class derived from Bar... isn't it?
 
I

Ian Collins

That's what I meant to say with "declaring Bar::createCopy() as
non-virtual". I guess the keyword is still needed if I want to further
redefine that function in a further class derived from Bar... isn't it?

No. Once a virtual, always a virtual. You can't redeclare a virtual
function as non-virtual.
 
S

Stuart Redmann

In Stanley Lippman's 'C++ Primer Fourth Edition', in page 564, the
following is mentioned:

"A virtual function in the derived class can return a reference or
pointer to a class that is PUBLICLY derived from the type returned by
the base class function."

I am unable to understand this sentence. Kindly explain it with
program sample.

I _guess_ that what he is talking about is the so-called co-variance
feature of C++ (see Stefan van Kessels posting). I have to admit that
the sentence can be mis-interpreted in many way. To put it better: A
virtual function f in the class D, which overwrites the same function
in the base class B, can return a type X that differs from the type Y
that is returned by B::f as long as Y deprecates to X. [this should
make it clear that X and Y must be pointers or references to classes
where Y is publicly derived directly or indirectly from X].

Regards,
Stuart
 
F

Francesco S. Carta

No. Once a virtual, always a virtual. You can't redeclare a virtual
function as non-virtual.

Ah, very good to know, that will save me some keystrokes in the future
;-) Thanks a lot for the clarification.
 
Ö

Öö Tiib

Ah, very good to know, that will save me some keystrokes in the future
;-) Thanks a lot for the clarification.

It is forbidden by some policies to use that "implicit virtuality"
feature.

Rationale is that it is already hard to notice that something is
override of virtual of base of base in C++ and omitted "virtual" makes
it even simpler to miss. Bugs with polymorphism are causing lot more
problems in practice than bad memory management.
 
Ö

Öö Tiib

(e-mail address removed):






Some compilers have support for declaring explicitly that the function is
intended to be a virtual override (eg. MSVC has the 'override' keyword
for that). If this is not the case (eg. because of mismatch of the
function signature) a compile-time error occurs. I find this feature
quite useful, but it means even more keystrokes (and is non-portable).

It can be perhaps macroed to portable if all in team are ready to use
it.

// put into platform specific configuration headers
#if defined(_MSC_VER) && (_MSC_VER >= 1400) // VS 2005+
# define OVERRIDE override
# pragma warning( disable : 4481 ) // nonstandard "override" used
#else
# define OVERRIDE
#endif

// example code
struct I
{
virtual void f();
};

struct X : public I
{
void f() OVERRIDE {}
};
 
Ö

Öö Tiib

  Isn't the first condition kind of redundant?

Yes it is, thanks for noticing. I first wrote that defined part then
thought that someone may still use MSVC 6.0 or VS 2003. Result didn't
hurt eye at Friday evening here.
 
J

James Kanze

(e-mail address removed), India <[email protected]>, on
IIUIC, that means that if you have a function with signature
"virtual Base* Clone() const;" in the base class, then the
implementation of the same function in the derived class can
be: "Base* Clone() const { return new Derived(*this); }"
- just an example that assumes Derived is copy-constructible,
of course.

I don't think that's what is meant (although it's hard to
say---the sentence is unclear, at least without its surrounding
context). I think the point here is covariant return types,
e.g.:

class Base
{
public:
virtual Base* someFunction();
};

class Derived : public Base
{
public:
virtual Derived* someFunction();
};
 
J

James Kanze

There is either something wrong in that sentence, in my understanding
or in my compiler - or my settings thereof - because it allows me to
return a pointer to Derived where Base is private:

In your understanding, I think, because...
//-------
#include <iostream>
using namespace std;
class Base {
public:
Base(int data = 0) : data(data) {};
Base(const Base& base) : data(base.data) {};
virtual Base* Clone() const {
cout << "cloning Base" << endl;
return new Base(*this);
}
int Data() const {
return data;
}
private:
int data;
};
class Derived : private Base {
public:
Derived(int data = 0) : Base(data) {};
Derived(const Derived& derived) : Base(derived) {};
Base* Clone() const {

Here, you're still returning a Base. Any conversion takes place
in Derived (where the derivation is visible).

Try changing the return type to Derived*; the compiler should
complain then.

See §10.3/5 in the standard for details.
 
R

red floyd

In your understanding, I think, because...




Here, you're still returning a Base. Any conversion takes place
in Derived (where the derivation is visible).

Try changing the return type to Derived*; the compiler should
complain then.

See §10.3/5 in the standard for details.

James, I thought that the compiler should *not* complain if the
return type of Derived::Clone was Derived*. Isn't that a
covariant return type?
 
Ö

Öö Tiib

James, I thought that the compiler should *not* complain if the
return type of Derived::Clone was Derived*.  Isn't that a
covariant return type?

Did you eyeball §10.3/5? Base is not accessible base class of Derived
so it is not a covariant there by standard.
 

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,774
Messages
2,569,596
Members
45,141
Latest member
BlissKeto
Top