I don't understand why the following code does not compile:
#include <iostream>
using namespace std;
template<typename T>
class Base {
public:
void printTuple(T tuple) {
std::cout << "Hello1!" << std::endl;
}
};
template<typename T>
class Derived : public Base<T> {
public:
void printTuple(std::string name, T tuple) {
std::cout << "Hello2!" << std::endl;
printTuple(tuple);
}
};
int main()
{
Derived<int> d1;
d1.printTuple("Test", 13);
return 0;
}
I get the following error:
main.cpp:19:25: error: no matching function for call to Derived::printTuple(int&)'
But shouldn't Derived inherit a method with such a signature from Base?
Thanks
You should change the line printTuple(tuple) to Base<T>::printTuple(tuple) because a function of the base class has been hidden.
Just add this to the top of the public part of class Derived:
using Base<T>::printTuple;
This will expose the base class overload of the function, i.e. prevent it from being "shadowed."
Related
Suppose I have a base class as below:
template <typename T>
class Base {
// implementation
void do_something() { /* ... */ } ;
};
then, I create a Derived class as below, and override the do_something() method:
template <typename T>
class Derived : public Base<T> {
// implementation
void do_something() { /* ... */ } ;
};
I know virtualization does not work in class templates, and I am just hiding the implementation of the methods. but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
my question is, given that static_cast of Derived class to base class gives me the do_something of based class, Is there any way that I can store them as base classes while each has their implementation of do_something() class ?
but I do want to store a bunch of derived classes and base classes into a vector, (I do not want to use type erasure, or polymorphism),
This is already just not possible in C++. In C++, a vector can only contain objects of the same static type. The only way a vector can contain different types of objects is if their static type is still the same, but they have different dynamic types, but this is type erasure/polymorphism which you said you don't want to use.
I think maybe you need to rethink your requirements, because your question in essence reads: I want to do something, but I don't want to use technique X which is explicitly defined as the only way to do that something in C++!
I did this and it seems to work fine:
#include <iostream>
template <typename T>
struct Base {
virtual void do_something() { std::cout << "Base::do_something()\n"; }
};
template <typename T>
struct Derived : public Base<T> {
virtual void do_something() { std::cout << "Derived::do_something()\n"; }
};
int main() {
Base<int> b;
Derived<int> d;
Base<int> *p;
p = &b;
p->do_something();
p = &d;
p->do_something();
return 0;
}
Output:
Base::do_something()
Derived::do_something()
A little variation of the melpomene's answer (adding a no-template base struct, BaseOfBase, for the Base<T> structs) permit the use of a common vector of base of derived classe of different T types.
A working example
#include <vector>
#include <iostream>
struct BaseOfBase
{ virtual void do_something () = 0; };
template <typename T>
struct Base : public BaseOfBase
{
T val;
void do_something ()
{ std::cout << "Base::do_something() [" << val << "]\n"; };
};
template <typename T>
struct Derived : public Base<T>
{ void do_something()
{ std::cout << "Derived::do_something() [" << this->val << "]\n"; } };
int main ()
{
std::vector<BaseOfBase*> vpbb;
Base<int> bi;
Derived<int> di;
Base<std::string> bs;
Derived<std::string> ds;
bi.val = 1;
di.val = 2;
bs.val = "foo";
ds.val = "bar";
vpbb.push_back(&bi);
vpbb.push_back(&di);
vpbb.push_back(&bs);
vpbb.push_back(&ds);
for ( auto const & pbb : vpbb )
pbb->do_something();
}
When we say virtualization doesn't work in template classes, we don't mean that you can't do virtual functions in a template class, nor does it mean that you cannot override a member function with a specialized version of it.
#melpomene showed an example of overriding in general, and I will show here with specialization:
#include <iostream>
template <typename T>
class Base {
public:
virtual T do_something(T in) { std::cout << "Base::do_something()\n"; return in; }
};
class Derived : public Base<int> {
public:
virtual int do_something(int in) { std::cout << "Derived::do_something()\n"; return in - 1; }
};
void main()
{
Base<int> b;
Derived d;
Base<int> *p = &b;
auto r1 = p->do_something(10);
std::cout << r1 <<std::endl;
p = &d;
auto r2 = p->do_something(10);
std::cout << r2 << std::endl;
}
Which will output
Base::do_something()
10
Derived::do_something()
9
Showing that it perfectly works as expected.
What we do mean when saying that
virtualization does not work in class templates
Basically means that you can't use as a template the derived class when the base is expected.
Consider the above classes Base<T> and Derived, then if we have the following code:
#include <memory>
template <typename T>
void Test(std::unique_ptr<Base<T>> in){ std::cout << "This will not work with derived"; }
void main()
{
Base<int> b;
Derived d;
auto ptr = std::unique_ptr<Derived>(&d);
Test(ptr); // <-- Will fail to compile as an invalid argument
}
it will fail because std::unique_ptr<Derived> does not inherit from std::unique_ptr<Base<T>> although Derived itself inherits from Base<T>.
Two methods for accessing template base class members are described here. When the base class member itself is a template, accessing it using the first method (this->) above is described here. Is there a way to use the second method (using xxxx) in this scenario as well?
For example, in the code below, is it possible to replace "????" with something to make the code work?
using namespace std;
template<typename T> class base
{
public:
template<bool good> void foo()
{
cout << "base::foo<" << boolalpha << good << ">()" << endl;
}
};
template<typename T> class derived : public base<T>
{
public:
using ????
void bar()
{
foo<true>();
}
};
Just for the record, even though it does not provide any answer or workaround, but I am currently working with VS Express 2013, and I can assure you that
#include <iostream>
template<typename T> class base
{
public:
template<bool good> void foo()
{
std::cout << "base::foo<" << good << ">()" << std::endl;
}
};
template<typename T> class derived : public base<T>
{
public:
void bar()
{
foo<true>();
}
};
struct A{};
void main() {
derived<A> a;
a.bar();
}
works perfectly fine...
How can I check whether my template parameters are derived from a certain base class? So that I am sure that the function Do can be called:
template<typename Ty1> class MyClass
{
...
void MyFunction();
};
template<typename Ty1> void MyClass<Ty1>::MyFunction()
{
Ty1 var;
var.Do();
}
Don't. If the method Do() doesn't exist in the class provided as an argument for Ty1, it will simply not compile.
Templates are a form of duck typing : the abilities of a class are not determined by what interface it inherits from, but by what functionality it actually exposes.
The advantage is that your template can then be used by any class with a suitable Do() method, regardless of where it came from or what bases it has.
You can achieve this using standard type trait is_base_of. Look at the example:
#include <iostream>
#include <type_traits>
using namespace std;
class Base {
public:
void foo () {}
};
class A : public Base {};
class B : public Base {};
class C {};
void exec (false_type) {
cout << "your type is not derived from Base" << endl;
}
void exec (true_type) {
cout << "your type is derived from Base" << endl;
}
template <typename T>
void verify () {
exec (typename is_base_of<Base, T>::type {});
}
int main (int argc, char** argv) {
verify<A> ();
verify<B> ();
verify<C> ();
return 0;
}
And the output is:
your type is derived from Base
your type is derived from Base
your type is not derived from Base
I have the case where I am deriving a class from two different base classes both having a static function with the same name.
To resolve this ambiguity, I tried to use the scope operator - just as I would do for a member function. However This does not compile. Why? Wrong syntax?
I want to call the static function via the derived typename and not directly via base class name. Actually I would like prefer to prevent this case, but I have no idea how to do so.
The error (commented out) in the code below also occurs, when I leave the templates away:
#include <iostream>
template<class TDerived>
class StaticBaseA
{
public:
static void announce()
{
std::cout << "do something" << std::endl;
}
};
template<class TDerived>
class StaticBaseB
{
public:
static void announce()
{
std::cout << "do something else" << std::endl;
}
};
class Derived :
public StaticBaseA<Derived>
, public StaticBaseB<Derived>
{
using StaticBaseA<Derived>::announce;
};
class NonDerived {};
int main(int argc, char* argv[])
{
Derived::announce();
// What I want:
//Derived::StaticBaseB<Derived>::announce(); Error: "Undefined symbol 'StaticBaseB'
// What works, but what I don't want ...
StaticBaseB<Derived>::announce();
// ... because I would like to prevent this (however this is done):
StaticBaseB<NonDerived>::announce();
return 0;
}
Making "announce" protected in StaticBaseA and StaticBaseB might be part-way to doing what you want.
You then could not call StaticBaseB<NonDerived>::announce from main as it would be inaccessible. You could call it from a class derived from StaticBaseB.
In other words:
template<class TDerived>
class StaticBaseA
{
protected:
static void announce()
{
std::cout << "do something" << std::endl;
}
};
template<class TDerived>
class StaticBaseB
{
protected:
static void announce()
{
std::cout << "do something else" << std::endl;
}
};
In Derived you have to promote "announce" to public.
class Derived : public StaticA<Derived>, public StaticB<Derived >
{
public:
using StaticA<Derived>::announce;
};
int main()
{
Derived::announce(); // legal and calls StaticBaseA::announce
NotDerived::announce(); // no such function
StaticBaseA< Derived >::announce(); // not accessible
StaticBaseB< Derived >::announce(); // also not accessible
StaticBaseA< NotDerived >::announce(); // not accessible
StaticBaseB< NotDerived >::announce(); // also not accessible
}
I have this CRTP with an incomplete child class that is missing a method that is "not really" implemented in the base class:
#include <iostream>
using namespace std;
template<class T>
class BaseA
{
public:
T& asChild(){return static_cast<T&>(*this);}
void AMethod(void) {asChild().AMethod();}
};
class IncompleteChild : public BaseA<IncompleteChild>
{
public:
// uncomment the following to avoid segfault:
// void AMethod(void) {cout << "IncompleteChild Method" << endl;}
};
class Child : public BaseA<Child>
{
public:
void AMethod(void) {cout << "Child AMethod" << endl;}
};
template<class T>
void printBaseA(BaseA<T>& a)
{
a.AMethod();
}
int main()
{
IncompleteChild cI;
cI.AMethod();
printBaseA(cI);
return 0;
}
This compiles fine, but results in a segmentation fault at runtime. How can I avoid that? I'd prefer a compiler error here (using gcc 4.6.3).
Since your class doesn't actually have a member AMethod, you end up calling the member of the CRTP base, which gives you infinite recursion.
The simple solution is not to reuse names all over the place, but have one called AMethod and the other AMethodImpl or something like that:
void AMethod()
{
static_cast<T*>(this)->AMethodImpl();
}