Pointer derived from pure virtual class(A) can't access overload method from the pure class (B)

101 views Asked by At

Consider I have two pure virtual classes, one deriving from the another and a concrete class deriving from the last mentioned:

#include <iostream>
#include <string>

class Abstract1
{
public:
    virtual ~Abstract1() { };
    virtual void method(int a) = 0;

protected:
    Abstract1() = default;
};

class Abstract2: public Abstract1
{
public:
    virtual ~Abstract2() { };
    virtual void method(char c, std::string s) = 0;

protected:
    Abstract2() = default;
};

class Concrete : public Abstract2
{
public:
    void method(int a) override
    {
        std::cout << __PRETTY_FUNCTION__ << "a: " << a << std::endl;
    }

    void method(char c, std::string s) override
    {
        std::cout << __PRETTY_FUNCTION__ << "c: " << c << "; s: " << s << std::endl;
    }
};

When I create a pointer of the type Abstract2* I can't have access to the override method from Abstract1.

int main()
{
    Concrete c;
    c.method(42);
    c.method('a', std::string("string"));

    Abstract2 *ptr_a2 = &c;
    ptr_a2->method(13); //Error
    ptr_a2->method('b', std::string("string2"));
}

I got the following error, saying that the only existing method is the Absctract2 overloaded:

<source>: In function 'int main()':
<source>:49:22: error: no matching function for call to 'Abstract2::method(int)'

   49 |     ptr_a2->method(13);

      |                      ^

<source>:22:18: note: candidate: 'virtual void Abstract2::method(char, std::string)'

   22 |     virtual void method(char c, std::string s) = 0;

      |                  ^~~~~~

<source>:22:18: note:   candidate expects 2 arguments, 1 provided

Does anybody know why does it happen or how to fix it? I mean, the only reasonable solution I got was to add

virtual void method(int a) override = 0;

inside Abstract2 class.

Is it a case of "name hiding"? Why only on pointer and not on the Concrete class then? The number of parameters are different is not only a close-type thing.

Here's a link to play with it online where the example was created: https://godbolt.org/z/gxKpzN

1

There are 1 answers

3
Toby Speight On

Yes, the name is hidden in Abstract2 (but visible again in Concrete, where the override is declared). The easiest way to make it accessible in Abstract2 is to add a using statement:

class Abstract2: public Abstract1
{
public:
    using Abstract1::method;
    virtual void method(char c, std::string s) = 0;
};

Note that it's not relevant whether the member function is pure virtual or has a definition, and we see the same whether looking at a concrete Abstract2 or a reference or pointer to type Abstract2.