Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 554
Paiusco Avatar asked Jan 15 '20 17:01

Paiusco


1 Answers

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.

like image 197
Toby Speight Avatar answered Oct 24 '22 06:10

Toby Speight