Вопрос

I'm having a weird issue with inheritance and method resolution in my class hierarchy. The code is being compiled with clang++ 5.0 with -O0. I have two classes like so:

class PrintBase
{
protected:
    static wstring_convert<codecvt_utf8<wchar_t>> sConverter;

public:
    virtual void PrintChar(wchar_t ch) = 0;
    inline  void PrintChar(char ch)
    {
        PrintChar(sConverter.from_bytes(ch)[0]);
    }

    virtual void PrintString(const wstring& str) = 0;
    inline  void PrintString(const string& str)
    {
        PrintString(sConverter.from_bytes(str));
    }
};

class Print: public PrintBase
{
public:
    virtual void PrintChar(wchar_t ch) override;
    virtual void PrintString(const wstring& str) override;
};

void Print::PrintChar(wchar_t ch)
{
    // do stuff
}

void Print::PrintString(const wstring& str)
{
    // do stuff
}

If I construct a Print instance Print* pnt = new Print(); and call pnt->PrintChar('c'); it correctly calls the inline base class method, does the conversion, and then correctly calls the implemented virtual override in the derived class.

If I call pnt->PrintString("test"); or pnt->PrintString(string("test")); or pnt->PrintString(someString); I get the error:

No viable conversion from 'basic_string<char, char_traits<char>, allocator<char>>' to 'const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t>>'

...with some variation on the constness of the of the "from" type. Calling pnt->PrintString(L"test"); or the like will work as one would expect. And I can force it to call the inline string& function with pnt->PrintBase::PrintString("test");

Why would it be able to correctly resolve and call the inline char method in the base class, but be unable to do so for the string& method without explicitly resolving the scope?

Это было полезно?

Решение

The setup you have is a classic example of an overriding function hiding other inherited overloads.

When a function is overridden in a derived class, that overriding function hides all the other overloads from the base class. Overload resolution comes after selecting the name, so once PrintString is determined to refer to Print::PrintString, it will never consider PrintBase::PrintString, even if the former does not accept the arguments being supplied and the latter would.

The most straightforward way is to bring in the inherited, but not overridden names into the derived class with a using declaration:

class Print: public PrintBase
{
public:
    virtual void PrintChar(wchar_t ch) override;
    using PrintBase::PrintChar;

    virtual void PrintString(const wstring& str) override;
    using PrintBase::PrintString;
};

I don't believe calling PrintChar('x') through a Print object actually calls the inline overload. What it would really do is initialise the wchar_t from the char you pass in. Is it possible it just does the same thing as the inline version would in your case?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top