I have a class that inherits from a base class. The derived class has a template method. The base class has a specialized version of this method:
#include <iostream>
class Base {
public:
static void print(int i) { std::cout << "Base::print\n"; }
};
class Derived : public Base {
public:
static void print(bool b) { std::cout << "Derived::bool_print\n"; }
template <typename T>
static void print(T t) { std::cout << "Derived::print\n"; }
void Foo() {
print(1);
print(true);
print("foo");
}
};
int main()
{
Derived d;
d.Foo();
return 0;
}
The output is:
Derived::print
Derived::bool_print
Derived::print
The desired output is:
Base::print
Derived::bool_print
Derived::print
See code at https://onlinegdb.com/BY2znq8WV
Is there any way to tell Derived::Foo to use the specialization from Base instead of using the unspecialized version define in Derived?
Edit
The above example might be oversimplified as #Erdal Küçük showed. In actuality Derived subclasses from Base using CRTP, so it is not known if Base has a print method. A fuller example can be found at https://onlinegdb.com/N2IKgp0FY
This might help:
class Derived : public Base {
public:
using Base::print; //one of the many useful usages of the keyword 'using'
//...
};
See: Using-declaration in class definition
Related
When I create a templated class with a virtual function, and override the function in a derived class, the base function still tries to get compiled.
Here is the minimal reproducible example:
#include <iostream>
template<typename T>
class Base
{
public:
virtual void Method()
{
static_assert(false);
}
};
class Derived : public Base<int>
{
public:
void Method() override
{
std::cout << "Hello, World!";
}
};
int main()
{
Derived d{};
d.Method();
return 0;
}
Why does the base method still try to compile when it is overriden?
First, it needs to be compiled as user can instantiate Base<T> and directly call Method() on it. If you wanted to make it non-callable, use virtual void Method() = 0; for abstract functions.
Second, not only compiled, it's actually accessible from Derived: you can call it e.g. from Derived::Method(), as Base<int>::Method().
My problem is that I can't chain methods from Derived class when I already used Base class methods. I tried to mix topmost answers from Returning a reference to the derived class from a base class method and CRTP and multilevel inheritance, but the problem is one of them is always returning the same object, the other is returning void. I want Base class being able to be inherited by any other class.
[The naive solution to this problem is to make a() virtual and override it in class Derived. But what if Base is inherited by 100 other classes and have 100 other methods to override? This is not scaling good.]
[The other naive solution is to call methods from Derived class first, then from Base, but... just no]
So, is it possible to somehow compile the following snippet in native C++? (I am not interested in boost solutions). It would be ideal if main()'s code wouldn't change.
#include <iostream>
#include <type_traits>
template <typename T = void>
class Base
{
public:
T& a();
};
class Derived : public Base<Derived>
{
public:
Derived& b() {std::cout << "b\n"; return *this;}
};
int main()
{
Base base;
base
.a()
;
Derived derived;
derived
.a()
.b()
;
return 0;
}
template <typename T>
T& Base<T>::a()
{
std::cout << "a\n";
if(std::is_same<T, void>::value)
{
return *this;
}
else
{
return static_cast<T&>(*this);
}
}
If only i could write template <typename T = Base> class Base { ... :)
Not sure if it is what you want, but with C++17 and if constexpr, you might do:
template <typename T = void>
class Base
{
public:
auto& a()
{
std::cout << "a\n";
if constexpr (std::is_same_v<T, void>) {
return *this;
} else {
return static_cast<T&>(*this);
}
}
};
Demo
Before, you might use specialization.
Expected this code to compile and work
template<class T>
class Base
{
virtual void method() = 0;
};
template<>
void Base<int>::method() { std::cout << "overrided" << std::endl; }
Base<int> base;
But it gives the 'Base<int>': cannot instantiate abstract class error. Thought partial specialization would make Base<int> non-abstract and allow to instantiate it.
Is there a working solution as short as this one and that keeps the Base class abstract? Otherwise I can make the Base class non-abstract or use Nicol Bolas's solution from here: Template specialization and inheritance
If it won't work for a non-template class, why should it work for a template class?
#include<iostream>
class Base
{
virtual void method() = 0;
};
void Base::method() { std::cout << "overrided" << std::endl; }
Base base;
errors:
10 : error: cannot declare variable 'base' to be of abstract type 'Base'
Base base;
^
3 : note: because the following virtual functions are pure within 'Base':
class Base
^
8 : note: virtual void Base::method()
void Base::method() { std::cout << "overrided" << std::endl; }
^
Compilation failed
What about specialization of whole class (instead of just one member function):
template<class T>
struct TempClass
{
virtual void f() = 0;
};
template <>
struct TempClass<int>
{
virtual void f()
{
//...
}
};
Note that TempClass<int> is no longer abstract class, but other Base classes are still abstract classes, (TempClass<float>, TempClass<double>, TempClass<SomeClassType>, ...).
and
it won't contain fields that generic class TempClass contains. You will have to copy-paste them from generic Base or, which is more clever solution,
you'll create base class with fields that both specialization have and then make those template classes inherit from that base class:
template <typename T>
struct Base
{
// some members that all Base classes have
};
template <typename T>
struct TempClass: Base<T>
{
virtual void f() = 0;
};
template <>
struct TempClass<int>: Base<int>
{
virtual void f()
{
//...
}
};
This way ugly copy-paste wasn't needed.
It is possible to provide an implementation of a pure virtual function in a class. That does not make the class instantiable.
class Base
{
virtual void method() = 0;
};
void Base::method() { /* Do something */ }
// This is still a problem since Base
// is still an abstract class, i.e. it is not still not
// instantiable.
Base base;
This question already has an answer here:
Simplest way to provide template specialization for derived classes
(1 answer)
Closed 8 years ago.
I want to specialize implementation of a template class if T was derived from a specific base class.
How can I do this?
In the code below, x.f() and y.f() should do different work.
I want to work not only for 'Derived' but also for all derived classes from Base.
#include <iostream>
class Base
{
};
class Derived : public Base
{
};
// If T not derived from Base:
template <typename T> class MyClass
{
public:
void f()
{
std::cout << "NOT derived from Base";
}
};
// If T derived from Base:
template <typename T> class MyClass
{
public:
void f()
{
std::cout << "Derived from Base";
}
};
int main()
{
MyClass<int> x;
MyClass<Derived> y;
x.f();
y.f();
}
Can use following :
#include <type_traits>
//If T not derived from Base:
template<class T, class Enable = void> class MyClass
{
public:
void f()
{
std::cout << "NOT derived from Base";
}
};
template<typename T>
class MyClass<T,typename std::enable_if<std::is_base_of<Base, T>::value>::type>
{
public:
void f()
{
std::cout << "\nDerived from Base";
}
};
See Here
I have a base class, say BassClass, with some fields, which I made them protected, and some pure virtual functions. Then the derived class, say DerivedClass, like class DerivedClass : public BassClass. Shouldn't DerivedClass inherit the protected fields from BassClass? When I tried to compile the DerivedClass, the compiler complains that DerivedClass does NOT have any of those fields, what is wrong here?
thanks
If BassClass (sic) and DerivedClass are templates, and the BassClass member you want to access from DerivedClass isn't specified as a dependent name, it will not be visible.
E.g.
template <typename T> class BaseClass {
protected:
int value;
};
template <typename T> class DerivedClass : public BaseClass<T> {
public:
int get_value() {return value;} // ERROR: value is not a dependent name
};
To gain access you need to give more information. For example, you might fully specify the member's name:
int get_value() {return BaseClass<T>::value;}
Or you might make it explicit that you're referring to a class member:
int get_value() {return this->value;}
This works:
#include <iostream>
struct Base {
virtual void print () const = 0;
protected:
int val;
};
struct Derived : Base {
void print () { std::cout << "Bases's val: " << val << std::endl; }
};