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