0

I'm a little confused about the following situations, are they correct ways for the overriding of function copy but not overloading, or all of them are right?

class Base{
public:
    virtual Base* copy(Base* b){...}
};

class Derived:public Base{
public:
    virtual Base* copy(Base* b){...}//I know this should work
 // but how about the followings?
    //virtual Base* copy(Derived* b){...}
    //virtual Derived* copy(Base* b){...}
    //virtual Derived* copy(Derived* b){...}
};

BTW, does the change of access right make any difference? say, I write the Derived class like this:

class Derived:public Base{
private://or protected:
    virtual Base* copy(Base* b){...}
    ...
};
2
  • I don't understand your question. Can you rephrase it? Are you asking about the rules for overriding virtual functions? Commented Aug 24, 2013 at 16:41
  • yes, I rephrase it now Commented Aug 24, 2013 at 16:42

3 Answers 3

6

These are the rules for function overriding:

[C++11: 10.3/2]: If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list (8.3.5), cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides111 Base::vf. [..]

If these rules are not met, then the new function does not override the old function (though it may overload or hide it).

So:

class Base
{
public:
    virtual Base* copy(Base* b);
};

class Derived : public Base
{
public:
    // Overrides Base::copy
    virtual Base* copy(Base* b);

    // Does NOT override Base::copy (due to different parameter-type-list)
    virtual Base* copy(Derived* b);

    // Overrides Base::copy (despite different return type)
    virtual Derived* copy(Base* b);

    // Does NOT override Base::copy (due to different parameter-type-list)
    virtual Derived* copy(Derived* b);

private:
    // Overrides Base::copy (despite different access specifier)
    virtual Base* copy(Base* b);
};

Though, note that the above class Derived is actually ill-formed, due to the end of 10.3/2 which states:

In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.

That means we should only have declared one of those overriding functions. I listed them all inside a single class definition just for the purpose of illustration.

It may be surprising that virtual Derived* copy(Base* b) overrides Base::copy, because it has a different return type; this is allowed as long as the two return types are covariant:

[C++11: 10.3/7]: The return type of an overriding function shall be either identical to the return type of the overridden function or covariant with the classes of the functions. If a function D::f overrides a function B::f, the return types of the functions are covariant if they satisfy the following criteria:

  • both are pointers to classes, both are lvalue references to classes, or both are rvalue references to classes
  • the class in the return type of B::f is the same class as the class in the return type of D::f, or is an unambiguous and accessible direct or indirect base class of the class in the return type of D::f
  • both pointers or references have the same cv-qualification and the class type in the return type of D::f has the same cv-qualification as or less cv-qualification than the class type in the return type of B::f.

As for the public vs private question, there is no rule saying that this matters; the situation is clarified by footnote 111 in case there was any doubt:

111 A function with the same name but a different parameter list (Clause 13) as a virtual function is not necessarily virtual and does not override. The use of the virtual specifier in the declaration of an overriding function is legal but redundant (has empty semantics). Access control (Clause 11) is not considered in determining overriding.

Sign up to request clarification or add additional context in comments.

3 Comments

You cannot, however, have both Derived* copy(Base* b) and Base* copy(Base* b) in Derived. The covariance does not mean you can have polymorphism based on return type.
@dan.p: My answer already explains that only one final overrider is allowed. You are right, though, of course.
Ah, sorry. I missed it embedded in all the interesting stuff.
3

They're all legal declarations, it's just that these two

virtual Base* copy(Derived* b);
virtual Derived* copy(Derived* b);

do not override the copy from the base class, as their signature is different. They just declare new virtual copy that hides the one from base.
This one, however

virtual Derived* copy(Base* b);

does override. It's got the same signature and a covariant return type.

In C++11 you can use override to force the compiler to emit an error if the function does not override anything:

virtual Derived* copy(Derived*) override { /*...  */} // will produce an error

Access right doesn't make any direct difference - it is checked based on the static type of the object. If the copy in base is public and you call it through a pointer to base class, it'll call the suitable overriding function even if it were private.

class Base {
public:
    virtual Base* copy(Base* b);
};

class Derived : public Base {
private:
    virtual Base* copy(Base* b);       // Overrides Base::copy
};

int main()
{
    Base* b = new Derived;
    Base* b2;
    b->copy(b2); // calls Derived::copy
    Derived d;
    d.copy(b2); // error, as expected
}

Comments

0

There already popped up two good answers while i was writing this, but i submit my anyway because it is written in another style. Maybe this more shallow answer is useful to someone.

First of all, it is a bit unclear with the copy method being part of an object, taking an object as input, and returning an object. Does it copy from or to the input? Does it return a copy or itself? Is it supposed to be static?

All of your declarations "work" (depending on what you wish to achieve), but not all of them together.

Edit: I removed the part disputed in the comments, the other answers covers that anyway. But i kept the part giving an example to explain why polymorphism on return type isn't allowed.

To only use implementations in Derived, you can declare

class Derived:public Base{
public:
    virtual Derived* copy(Base* b){...}; 
    virtual Derived* copy(Derived* b){}; 
};

or

class Derived:public Base{
public:
    virtual Base* copy(Base* b){...}; 
    virtual Derived* copy(Derived* b){}; 
};

Polymorphism based on return type is not supported in C++, however. You cannot use

class Derived:public Base{
public:
    virtual Base* copy(Derived* b){...}; 
    virtual Derived* copy(Derived* b){}; 
};

because the compiler will have trouble determining what to do if you do not use the result. Consider:

Derived * d = new Derived(); 

Derived * toCopy = new Derived(); 

Base * b2 = toCopy->copy(d); // Should use use the version returning Base

Derived * d2 = toCopy->copy(d); // Should use the version returning Derived

toCopy->copy(d2); // Which implementation should the compiler pick? It cannot know!

Because the compiler cannot decide on the version to use in the last line above, it is illegal to overload on return type.

As for the access right, i gladly recommend the other answers.

6 Comments

You've got two errors: Derived toCopyInto = new Derived(); and Derived toCopy = new Derived(); And overloading on return type is illegal for any function, be it virtual or not. Also Base b2 = toCopy.copy(d); is illegal, too.
@jrok, thank you for pointing out the errors. That overloading on return type is illegal was what i was trying to explain. I tried to clarify.
@Ghostblade You can invoke toCopyInto->(Base *) on Derived. It is Base::copy and not Derived::copy that will be invoked. Because Base:copy(Base *) is not overridden in this case.
@dan.p Base class's copy is hidden by Derived but not overridden, so if you want to invoke Base's copy from a pointer of Derived class, you should put using Base::copy in your class body
@dan.p Which means your toCopyInto->copy(b) will not compile
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.