Main Content

Incompatible types prevent overriding

Derived class method hides a virtual base class method instead of overriding it

Description

This defect occurs when a derived class method has the same name and number of parameters as a virtual base class method but:

  • The parameter lists differ in at least one parameter type.

  • The parameter lists differ in the presence or absence of qualifiers such as const.

The derived class method hides the virtual base class method instead of overriding it.

Risk

  • You might inadvertently hide the base class method instead of overriding it with the derived class method.

  • If the base class method is hidden and you use a derived class object to call the method with the base class parameters, the derived class method is called instead. For the parameters whose types do not match the arguments that you pass, a cast takes place if possible. Otherwise, a compilation failure occurs.

Fix

To override a base class virtual method with a derived class method, declare the methods by using identical parameter lists. For instance, change the parameter type or add a const qualifier if required.

In C++11 and later, you can declare intended overriding methods in the derived class by using the specifier override. When you declare the derived class methods by using the specifier override, the compilation fails if the parameter lists of the base class method and the derived class method are different. The derived class methods cannot hide base class methods inadvertently and overriding of the base class virtual methods is ensured.

Otherwise, add the line using Base_class_name::method_name to the derived class declaration. You can then access the base class method using an object of the derived class.

Examples

expand all

class Base {
public:
    Base();
    virtual ~Base();
    virtual void func(float i);
    virtual void funcp(float* i);
    virtual void funcr(float& i);
};

typedef double Float;

class Derived: public Base {
public:
    Derived();
    ~Derived();
    void func(Float i);
    void funcp(Float* i);
    void funcr(Float& i);
};

In this example, because of the statement typedef double Float;, the Derived class methods func, funcp, and funcr have double arguments while the Base class methods with the same name have float arguments. Therefore, you cannot access the Base class methods using a Derived class object.

The defect appears on the method that hides a base class method. To find which base class method is hidden:

  1. Navigate to the base class definition. On the Source pane, right-click the base class name and select Go To Definition.

  2. In the base class definition, identify the virtual method that has the same name as the derived class method name.

Correction — Unhide Base Class Method

One possible correction is to use the same argument type for the base and derived class methods to enable overriding. Otherwise, if you want to call the Base class methods with the float arguments using a Derived class object, add the line using Base::method_name to the Derived class declaration.

class Base {
public:
    Base();
    virtual ~Base();
    virtual void func(float i);
    virtual void funcp(float* i);
    virtual void funcr(float& i);
};

typedef double Float;

class Derived: public Base {
public:
    Derived();
    ~Derived();
    using Base::func;
    using Base::funcp;
    using Base::funcr;
    void func(Float i);
    void funcp(Float* i);
    void funcr(Float& i);
};
Correction — Specify Derived Class Method by using override

Another correction is to explicitly specify the derived class methods as overriding methods by using the specifier override. This way, it is clear that you intend to override the base class methods in the derived class. If the overriding methods have different parameter lists than their base class counterparts, the code does not compile. As a result, the derived class methods cannot hide the base class methods.

class Base {
public:
    Base();
    virtual ~Base();
    virtual void func(float i);
    virtual void funcp(float* i);
    virtual void funcr(float& i);
};

typedef double Float;

class Derived: public Base {
public:
    Derived();
    ~Derived();
//   Compilation error
//  void func(Float i) override;
//  void funcp(Float* i) override;
//  void funcr(Float& i) override;

    void func(float i) override;
    void funcp(float* i) override;
    void funcr(float& i) override;
};

The commented out method definitions have different parameter lists compared to their base class counterparts. Because the derived class methods are declared by using the specifier override, the differing parameter lists do not hide the base class methods. Instead, the code fails to compile. Using the override specifier enforces the rule that virtual methods in base and derived classes must have identical parameter lists.

namespace Missing_Const {
class Base {
public:
    virtual void func(int) const ;
    virtual ~Base() ;
} ;

class Derived : public Base {
public:
    virtual void func(int) ;

} ;
}

In this example, Derived::func does not have a const qualifier but Base::func does. Therefore, Derived::func does not override Base::func.

Correction — Add const Qualifier to Derived Class Method

To enable overriding, add the const qualifier to the derived class method declaration.

namespace Missing_Const {
class Base {
public:
    virtual void func(int) const ;
    virtual ~Base() ;
} ;

class Derived : public Base {
public:
    virtual void func(int) const;

} ;
}

To avoid hiding base class methods or turning virtual methods into nonvirtual methods unintentionally:

  • Declare virtual methods in the base class by using the specifier virtual.

  • Declare virtual methods in a nonfinal derived base class by using the specifier override.

  • Declare virtual methods in the final class by using the specifier final.

namespace Missing_Ref {

class Obj {
    int data;
};

class Base {
public:
    virtual void func(Obj& o);
    virtual ~Base() ;
} ;

class Derived : public Base {
public:
    virtual void func(Obj o) ;

} ;
}

In this example, Derived::func accepts an Obj parameter by value but Base::func accepts an Obj parameter by reference. Therefore, Derived::func does not override Base::func.

Correction — Use Reference for Parameter of Derived Class Method

To enable overriding, pass the derived class method parameter by reference.

namespace Missing_Ref {

class Obj {
    int data;
};

class Base {
public:
    virtual void func(Obj& o);
    virtual ~Base() ;
} ;

class Derived : public Base {
public:
    virtual void func(Obj& o) ;

} ;
}

To avoid hiding base class methods or turning virtual methods into nonvirtual methods unintentionally:

  • Declare virtual methods in the base class by using the specifier virtual.

  • Declare virtual methods in a nonfinal derived base class by using the specifier override.

  • Declare virtual methods in the final class by using the specifier final.

Result Information

Group: Object oriented
Language: C++
Default: On for handwritten code, off for generated code
Command-Line Syntax: VIRTUAL_FUNC_HIDING
Impact: Medium

Version History

Introduced in R2015b