Given the below class structure, I want to call a method in struct C<O> from a method in struct B. C<O> follows follows the curiously recurring template pattern. I want to do this without placing methods in struct O. Placing methods in struct O would defeat the purpose of struct C<>. I suspect that this is not possible, but thought I'd ask.
EDIT: the struct O can be any one of a set of types that have both struct B and struct C<O> as base classes.
struct B
{
virtual void foo ()
{
// dynamic_cast this to C<O>* and call C<O>::moo()
}
};
template <typename P>
struct C
{
virtual void moo () { }
};
struct O :
public B,
public C<O>
{
};
If you define foo out-of-line following the definition of O it works fine:
struct B
{
virtual void foo();
};
template <typename P>
struct C
{
virtual void moo() {}
};
struct O :
public B,
public C<O>
{
};
void B::foo()
{
dynamic_cast<C<O>*>(this)->moo();
}
So I suggest to get rid of CRTP and cast to C directly from B. Or at lest making C a non-template class and derive CRTP from it. This way multiple of various O classes won't matter.
struct C
{
virtual void moo () {}
};
struct B
{
virtual void foo ()
{
auto p_c{dynamic_cast<C *>(this)};
if(p_c)
{
p_c->moo();
}
}
};
struct O: public B, public C
{
};
int main()
{
O o;
o.foo();
}
Related
Suppose I have some class A:
// a.h:
class A {
virtual unsigned foo() {
return 0;
}
Then, I have many classes (let's call these intermediates) inheriting from A (class B, class C...etc). These classes will NEVER override foo().
// b.h:
class B : public A {
bool override_foo = true;
// ....
}
// c.h:
class C : public A {
bool override_foo = false;
}
Then, I have many classes inheriting from the intermediates. Class D, E, etc. Only one if these will ever inherit from a single intermediate, i.e, these is a 1 to 1 relationship between these classes and the intermediates. There is guaranteed to only (and always) be a single one of these classes inheriting from one of the intermediates.
Now, these classes MAY override foo. However, if they do, and the intermediate class they inherit from does not define override_foo as true, I need compilation to fail.
So, for example, if we have class D:
// d.h:
class D : public B {
unsigned foo() override();
}
Compilation would proceed fine, since B has override_foo defined as true.
However, we this should fail:
// e.h:
class E : public C {
unsigned foo() override();
}
Since C has override_foo as false.
Is this something that is achievable? Unfortunately there is very little flexibility in this problem. I work for a company where the intermediate classes, (B, C) can be changed very slightly. They are created from the compilation of a proprietary framework. I could add a member to them, or any sort of macro magic. Same for the base class A. However, the grandchildren classes, D,E, are defined by other engineers to override parts of the framework, and I need to prevent them from doing so unless the intermediate classes have some key attributes.
Thanks!
You can use final keyword to disallow inherited classes to override the method.
class A {
public:
virtual ~A() = default;
virtual void foo() {}
};
class B : public A {
public:
void foo() final { A::foo(); }
};
class C : public A {};
class D : public B {
public:
void foo() override; // <- compilation error here
};
class E : public C {
public:
void foo() override;
};
int main() {}
The other answers require your intermediate classes to override the base class version of foo() with final so the derived class can't override it instead of making a boolean member variable determine the result - and that would work. And maybe it is what you want, but it's not what you said you wanted. So I am going to answer the question you asked even though the other answers might be more what you were actually after.
If you can modify B then this makes the derived classes pretty simple to write:
#include <stdio.h>
#include <type_traits>
struct B {
virtual int foo() {
puts("B");
};
template<typename X>
using baseFooType = typename std::enable_if<X::override_foo,decltype(((B*)nullptr)->foo())>::type;
};
struct C : public B {
constexpr static bool override_foo = true;
};
struct D : public B {
constexpr static bool override_foo = true;
};
struct E : public C {
baseFooType<C> foo() override {
puts("E");
}
};
struct F : public D {
baseFooType<D> foo() override {
puts("F");
}
};
int main()
{
E().foo();
F().foo();
}
Try it here: https://onlinegdb.com/rJe5jXQhHI
If you can't modiby B then you can use a helper class like this:
#include <stdio.h>
#include <type_traits>
struct B {
virtual int foo() {
puts("B");
};
};
template<typename X>
struct baseFooType {
using type = typename std::enable_if<X::override_foo,decltype(((B*)nullptr)->foo())>::type;
};
struct C : public B {
constexpr static bool override_foo = true;
};
struct D : public B {
constexpr static bool override_foo = true;
};
struct E : public C {
baseFooType<C>::type foo() override {
puts("E");
}
};
struct F : public D {
baseFooType<D>::type foo() override {
puts("F");
}
};
int main()
{
E().foo();
F().foo();
}
Try it here: https://onlinegdb.com/BJXg4QhB8
Note: I used constexpr in the example because I thought it would need that to be passed as a template parameter but it turns out it isn't needed - you can just use const instead.
You can do everything your asking with the final keyword (c++11).
Like in other languages the final keyword prevents a method being overloaded in a derived class, or can be used to prevent a class from being derived from altoghether!
For example
class A: public X {
void foo() final; // <-- Overrides foo() in X
};
class B: public A {
void foo() override; // <-- Compile error! foo() has been declared final!
};
This works at compile time and will throw you a nice compile error :) Final also implies virtual and override (if it overrides something).
The code below won't compile:
struct Base
{
std::vector<void(Base::*)(void)> x;
};
struct Derived : public Base
{
void foo() {}
};
// ...
Derived d;
d.x.push_back(&Derived::foo);
Is it possible to refer derived class in template member x? In the example above I specify exactly Base and derived classes cannot push their own member functions into vector x.
Casting is bad since your code have to assume that this will be called only for instance of Derived class. This means that you either have to assume that all items in x are instance of Derived (in such case declaration of x is to general and should be changed to std::vector<void(Derived::*)(void)> x;) or you have to maintain extra information what which class method is stored in specific position of x. Both approaches are bad.
In modern C++ it is much better do do it like this:
struct Base
{
std::vector<std::function<void()>> x;
};
struct Derived : public Base
{
void foo() {}
};
// ...
Derived d;
d.x.push_back([&d](){ d.foo(); });
Another good approach can be CRTP:
template<class T>
struct Base
{
std::vector<void(T::*)(void)> x;
};
struct Derived : public Base<Derived>
{
void foo() {}
};
// ...
Derived d;
d.x.push_back(&Derived::foo);
You may, but there is no implicit conversion; it requires a cast.
Derived d;
d.x.push_back(static_cast<void(Base::*)()>(&Derived::foo));
The caveat is the if you use that pointer to member with an object that isn't really a Derived, the behavior is undefined. Tread carefully.
As an addendum, if you want to get rid of the cast when taking the pointer, you can do that by encapsulating the push (with some static type checking to boot):
struct Base
{
std::vector<void(Base::*)(void)> x;
template<class D>
auto push_member(void (D::* p)()) ->
std::enable_if_t<std::is_base_of<Base, D>::value> {
x.push_back(static_cast<void(Base::*)()>(p));
}
};
I think I would express this by calling through a non-virtual member function on the base.
example:
#include <vector>
struct Base
{
std::vector<void(Base::*)(void)> x;
// public non-virtual interface
void perform_foo()
{
foo();
}
private:
// private virtual interface for the implementation
virtual void foo() = 0;
};
struct Derived : public Base
{
private:
// override private virtual interface
void foo() override {}
};
// ...
int main()
{
Derived d;
d.x.push_back(&Base::perform_foo);
auto call_them = [](Base& b)
{
for (auto&& item : b.x)
{
(b.*item)();
}
};
call_them(d);
}
I have a parent-class with a function. In this function I want to call a template method but the type of the template depends on the type of sub-class. So I want to save the information about T there. I can't call foo with a template because it's from another part of the Program wich i can't change
class A
{
//this will be called on an instance of B or C, A will never be
//instantiated
void foo()
{
ba<T>();
}
}
class B :public A
{
//T want to save here the Type of T so i won't have to call foo() with
//a template
}
class C :public A
{
//here comes another Type for T
}
What you need is a CRTP pattern, which is very common in C++ template programming.
template<class T>
void ba() {}
template<class Derived>
struct A
{
void foo() {
ba<typename Derived::MyT>();
}
};
struct B
: public A<B>
{
using MyT = int;
};
struct C
: public A<C>
{
using MyT = double;
};
int main() {
B b;
b.foo();
C c;
c.foo();
}
You will need to add a template parameter to the base class A and then specify the type in the declaration of B and C. See the example below:
template <typename T>
class A
{
public:
void foo()
{
ba<T>();
}
};
class B : public A<int>
{
};
class C : public A<bool>
{
};
int main()
{
B b;
C c;
b.foo(); // This calls ba<int>()
c.foo(); // This calls ba<bool>()
return 0;
}
It might be good to spend some time reviewing how templates and inheritance work.
Inheritance
Templates
I'm not sure if the following code is going to do what I expect it to:
struct Foo
{
// Some variables
};
struct Bar : public Foo
{
// Some more variables
};
struct Baz : public Foo
{
// Some more variables
};
class ExampleBase
{
Foo* A;
int B;
double C;
};
class ExampleBar : public ExampleBase
{
Bar* A;
}
class ExampleBaz : public ExampleBase
{
Baz* A;
}
void DoStuff(ExampleBase& example)
{
// Does things with the Foo*, doesn't need to know what inherited type it is
}
What happens when I have the same name for a pointer (A), which is derived from the same class, but is redefined in the derived Example classes?
I've tried templating the example class like this in order to avoid any ambiguity:
template <typename T>
class ExampleBase
{
T* A;
int B;
double C;
}
And then not deriving any classes from it. When I did this however, I can't get the DoStuff() function to compile. since I want it to accept any of the possible derived types.
Edit: The answers from the possible duplicate explain what happens, but don't solve the issue of a function using the base version
You may want to use a template for to implement DoStuff:
template<typename T>
void DoStuff(ExampleBase<T>& example)
{
// Does things with the T*
}
Alternatively, you can expose both the template and the polymorphic interface separately:
struct ExampleBase
{
int B;
double C;
virtual Foo* getA();
};
template<typename T>
struct ExampleTBase : ExampleBase
{
T* A;
Foo* getA() override { return A; }
};
void DoStuff(ExampleBase& example)
{
// Does things with the getA(), that returns a Foo*
}
Suppose I have the following class definitions
struct base {
virtual int f() = 0;
};
struct A: public base {
int f() final { return 1; }
};
struct B: public base {
int f() final { return 2; }
};
Is it possible to turn A and B into templates that take a bool parameter that specifies whether to inherit from the base or not? I have usage cases that do or don't require a base class providing a common interface.
Assume that A and B have a lot of member functions, so duplicating implementation would be tedious. But sizeof(A) and sizeof(B) are small.
Sure:
template <bool> struct A
{
// ...
};
template <> struct A<true> : base
{
// ...
};
(Note that you could make A<true> derive from A<false> if that avoids redundancy.)
For example:
template <bool> struct A
{
void f() { std::cout << "A::f called\n"; }
};
template <> struct A<true> : A<false>, base
{
void f() override { A<false>::f(); }
};
int main()
{
A<false> a1;
A<true> a2;
a1.f();
a2.f();
static_cast<base&>(a2).f();
}
I came up with the more direct approach I was looking for, without code duplication.
struct base {
virtual int f() = 0;
};
struct empty_base { };
template <bool Inherit>
struct A final: public std::conditional_t<Inherit,base,empty_base> {
int f() { return 1; }
};
Since you are using a pure base class the distinction shouldn't be important as your optimizer will avoid the virtual function call when you call A::f() since there will never be a derived class that implements a different version of f().
Also you can instead do class A final : base if you don't plan on inheriting from A to avoid having to add final to each function.