I'm currently learning C++ and have come across the following problem: I have a templated interface BaseTemplate, which I would like to implement in a Child class without making the child a template itself. Sample code is as follows:
template <typename T>
class BaseTemplate
{
    public:
        virtual const T get() const = 0;
};
class Child : public BaseTemplate<int*>
{
    public:
        Child(int value) : myInt{value} {};
        virtual const int* get() const override { return &myInt; };
    private:
        int myInt{0};
};
int main()
{
    Child myChild = Child(10);
    std::cout << myChild.get() << "\n";
    return 0;
}
GCC produces the following error:
main.cpp|16|error: conflicting return type specified for ‘virtual const int* Child::get() const’
main.cpp|9|note: overridden function is ‘const T BaseTemplate<T>::get() const [with T = int*]’
I clearly understand that the error is related to
virtual const int* get() const override { return &myInt; }; but I don't understand what's the problem. If I change the return type (of course in both classes) to int, i. e. return a value instead of a pointer, it works fine. So what's wrong with pointers here?
Maybe it helps: in my actual code, I want return a pointer to a custom interface instead of int, the error there is related I believe
file_trees.h|19|error: invalid covariant return type for ‘virtual const IDirectoryNode* FileTree::DepthFirstIterator::getCurrent() const’
iterator_interface.h|10|note: overridden function is ‘const T IIterator<T>::getCurrent() const [with T = IDirectoryNode*]’
                It has to due how const applies to types.
const T means the returned value is constant (that is of course almost useless). For pointers, this means the pointer itself is constant, not its target.
On the other hand, const int* is a non-constant pointer to a const int value.
For Base<int*>, T=int* yields int* const, not const* int, so you have to define int* const get() virtual method.
For T=const int* it would be const int* const. See this question for more details.
When you have a
int *
The constant version of this type is not const int *. It is int * const, or a constant pointer to an int.  const int * is a pointer to a constant int, which is a completely different type.
However, fixing the return type is insufficient, because get() is a const class method. Taking a pointer to it's data pointer produces a const int *, rather than an int *.
Probably the simplest fix here is to make this class member mutable:
class Child : public BaseTemplate<int*>
{
    public:
        Child(int value) : myInt{value} {};
        virtual int *const get() const override { return &myInt; };
    private:
        mutable int myInt{0};
};
Without fundamentally redesigning the entire class hierarchy, this is the minimal fix to get this to compile. You should fully understand what it means to make a class member mutable, and understand all implications.
The const version of int* is int* const, which is a constant pointer to integer type, not pointer to const int.
What you intended could be achieved in the following way.
template<class T>
struct const_type_handler
{
    using type=const T;
};
template<class T>
struct const_type_handler<T*>
{
    using type=const T*;
};
template <typename T>
class BaseTemplate
{
    public:
        virtual typename const_type_handler<T>::type get() const = 0;
};
class Child : public BaseTemplate<int*>
{
    public:
        Child(int value) : myInt{value} {};
        virtual typename const_type_handler<int*>::type get() const override { return &myInt; };
    private:
        int myInt{0};
};
I know this makes the code kinda messy, but it works!.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With