On 03/11/2018 10:56 PM, Lynn McGuire wrote:
> On 3/10/2018 6:11 PM, Ian Collins wrote:
>> On 03/11/2018 01:03 PM, Lynn McGuire wrote:
>>> On 3/9/2018 11:28 PM, Alf P. Steinbach wrote:
>>>> On 10.03.2018 04:50, Lynn McGuire wrote:
>>>>> OK, to simplify, I have the following classes:
>>>>>
>>>>> class ObjPtr;
>>>>> class DataItem : public ObjPtr;
>>>>> class DataGroup : public ObjPtr;
>>>>> class CrudeGroup : public DataGroup;
>>>>>
>>>>> I have a base method in ObjPtr:
>>>>> virtual ObjPtr * dataTransferItemsToDIIW (int key);
>>>>>
>>>>> I have a method in CrudeGroup:
>>>>> virtual DataItem * dataTransferItemsToDIIW (int key);
>>>>>
>>>>> Why am I not getting a compiler error from Visual Studio C++ 2015 that
>>>>> the return types do not match ?
>>>>>
>>>>> Is it because I am not using the override keyword in the function
>>>>> declaration ?
>>>>>
http://en.cppreference.com/w/cpp/language/override
Alf has already given a good answer this question, but I'm answering it
in more detail with citations from the standard below, so I'm clipping
his answer.
>>> So I do need to use the override keyword always in order to get a proper
>>> method lookup. Bummer.
>>
>> No, you don't. Why do you object to using it?
>
> in DCrudeOptionsDialog::command, I call:
> CrudeGroup * crudeGroup = owner -> getCrudeGroup;
>
> this gives me the ObjPtr method instead of the CrudeGroup method:
> ObjPtr * anObject = crudeGroup -> dataTransferItemsToDIIW (key);
I wrote the simplest program I could come up with that contains all of
the actual lines of code that you've provided, and is consistent with
the descriptions you've give us, and is instrumented to produce output
addressing the issues you've raised. It is, I believe, well-formed code
with standard-defined behavior. As you can see from the output, it calls
the CrudeGroup version of dataTransferItemsToDIIW:
~/Programming/C++/testprog(70) cat covariant_return.cpp
// Based upon a message posted by Lynn McGuire <
lynnmc...@gmail.com>
// to comp.lang.c++ with Date:Fri, 9 Mar 2018 21:50:13 -0600.
#include <iostream>
class ObjPtr
{
public:
virtual ObjPtr * dataTransferItemsToDIIW (int key){
std::cout << this << " ObjPtr::dataTransferItemsToDIIW(" << key
<< ")" << std::endl;
return this;
};
virtual ~ObjPtr() {};
};
class DataItem : public ObjPtr{
};
class DataGroup : public ObjPtr{
};
class CrudeGroup : public DataGroup
{
public:
virtual CrudeGroup * dataTransferItemsToDIIW (int key){
std::cout << this << " CrudeGroup::dataTransferItemsToDIIW(" <<
key << ")" << std::endl;
return this;
};
} crudeGroup;
struct Owner{
CrudeGroup *getCrudeGroup;
} actual = {&crudeGroup}, *owner = &actual;
struct DCrudeOptionsDialog
{
void command(int key)
{
CrudeGroup * crudeGroup = owner -> getCrudeGroup;
ObjPtr * anObject = crudeGroup -> dataTransferItemsToDIIW (key);
std::cout << "owner:" << owner << " crudeGroup:" << crudeGroup
<< " anObject:" << anObject << std::endl;
}
} dialog;
int main(void)
{
dialog.command(0);
}
~/Programming/C++/testprog(71) g++ -std=c++1y -pedantic -Wall
-Wpointer-arith -Wcast-align -fno-enforce-eh-specs -ffor-scope
-fno-gnu-keywords -fno-nonansi-builtins -Wctor-dtor-privacy
-Wnon-virtual-dtor -Wold-style-cast -Woverloaded-virtual -Wsign-promo
covariant_return.cpp -o covariant_return
~/Programming/C++/testprog(72) ./covariant_return
0x602078 CrudeGroup::dataTransferItemsToDIIW(0)
owner:0x602080 crudeGroup:0x602078 anObject:0x602078
> This is because the ObjPtr and CrudeGroup methods have different return
> types.
Which is permitted - section 10.3p7 says:
"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:
(7.1) — both are pointers to classes, both are lvalue references to
classes, or both are rvalue references to classes 112
(7.2) — 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
(7.3) — 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."
> ... The only way that I see to force the compiler to flag the
> improper return type is to use the override keyword.
It's not improper, so there's no need to flag it. The sole effect of the
"override" keyword is to make it an error if the function it applies to
does NOT override a virtual member of one of it's base classes.
The return type has nothing to do with whether something is a function
override. The requirements for being an override are:
"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 overrides 111 Base::vf." (10.3p2)
It's an error for an overriding function to have a return type that
violates 10.3p7, but it's still an override, or 10.3p7 wouldn't even
apply. Therefore, if "override" causes an error message, it's because,
in your actual code, there is some feature that causes
CrudeGroup::dataTransferItemsToDIIW() to fail to qualify as an override
of ObjPtr::dataTransferItemsToDIIW(). There's no such reason in the code
you've posted, so there's probably a relevant difference between your
actual code and the code you posted. When I inserted the override
keyword in my code, I got no complaint.
> ... The compiler is
> allowing the multiple return types until I tell it to only allow one
> return type by use of the override keyword.
That's NOT what the override keyword tells it.