Search code examples
c++inheritanceg++virtualcovariance

deprecated covariant return type for virtual


hi everyone i get some warnings while compiling my code with codeblocks which don't know what does it mean, should ignore them or that would reflect on my program during its execution

\src\..\inc\UTDB_Field.h|56|warning: deprecated covariant return type for 'virtual int* UTDB_intField::get_valField() const'
\src\..\inc\UTDB_Field.h|19|warning: overriding 'virtual void* UTDB_Field::get_valField() const'

In fact virtual void* UTDB_Field::get_valField() const const is a pure virtual function in UTDB_Field(the base class) and virtual int* UTDB_intField::get_valField() const const is the derived's one(UTDB_intField).

i found several explanations of what does co variant return type means but what i understood is that the return type void* (in my case) is lost and was replaced by int*, for me that is is my goal i want a generic type of return and each derived class will take in charge of its own.

here is my operator== defined in the derived class UTDB_intField:

 virtual bool operator==(const UTDB_Field& Field) const
{
     if(this->typeF==(Field.get_typeField()))
      {
           if(this->nameF==(Field.get_nameField()))
           {
                if (this->val== Field.get_valField())
                return true;
                else
                {
                    std::cout<<" val 1: "<<*(this->get_valField())<<" and val2:  "<<*(int*)Field.get_valField() <<" are different"<<std::endl;
                    return false;
                }
            }
            else
                {
                    std::cout<<" name 1: "<<this->get_nameField()<<" and name 2: "<<Field.get_nameField() <<" are different"<<std::endl;
                    return false;
                }
      }
      else  {
                std::cout<<" type "<<this->typeF<<" and "<<Field.get_typeField() <<" are two incomparable types"<<std::endl;
                return false;
            }
};

when i test it with this :

string  a="CurrField";
string* val=&a;
int b=5;
int* val2=&b;

std::cout<<"  *Construction*"<<endl;

UTDB_Field* UTField=new UTDB_strField("name",val);

UTDB_Field* UTField2=new UTDB_intField("Currency",val2);

std::cout<<" --------------- "<<std::endl;
std::cout<<"result of comparison "<<(*UTField2==(*UTField))<<endl;

i get my message: type int and str are two incomparable types

result of comparison 0

So if the tow Fields have the same type it is OK i know what type i have, but if they doesn't i should have the message of incompatibility.

any help will be appreciated

thanks in advance


Solution

  • Setting aside design considerations and opinions, the only real problem here is that you are outside the standard and it won't compile with other compilers. The reason is that the standard only allows return types to differ by covariance. In other words the return type from an overload must be the same type as the base method; or a derived type that implicitly casts to the base. This assumes returns are by pointer/ref.

    The intent of covariant return types (typically) was so that class A could have a method that returned a 'A *' from some routine. Class B derives from A and overloads that methods, but would really like to return a 'B *'. Sure it can say it returns an 'A *' since that is a 'B *', but you'd like the extra info.

    This way if someone is using an object of type B and it's known to be B, it can leverage the knowledge that the method is returning (at least) a B* without having to upcast.

    What you've done here is awkward, but logically fine. If you use the object as a UTDB_Field* the method is giving you a void* that could be anything. If you use it as a UTDB_IntField*, which it hopefully really is, then you have the extra info from the prototype that what's being returned is more than a void , and is indeed an int.

    I won't go into if this is good or bad, but it may be important for you to know about the portability problem taking this to other compilers.