Determine, at compile time, whether virtual method has been overridden - c++

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).

Related

Multiple inheritance in c++ using abstract base classes [duplicate]

I tried this code:
class A
{
virtual void foo() = 0;
};
class B
{
virtual void foo() = 0;
};
class C : public A, public B
{
//virtual void A::foo(){}
//virtual void B::foo(){}
virtual void A::foo();
virtual void B::foo();
};
void C::A::foo(){}
void C::B::foo(){}
int main()
{
C c;
return 0;
}
It is OK when using the commented part, but when I try to write the definitions outside the class declaration, the compiler reports errors.
I am using the MSVC11 compiler, does anyone know how to write this?
I need to move the code into the cpp file.
Thank you~~
A function overrides a virtual function of a base class based on the name and parameter types (see below). Therefore, your class C has two virtual functions foo, one inherited from each A and B. But a function void C::foo() overrides both:
[class.virtual]/2
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.
As I already stated in the comments, [dcl.meaning]/1 forbids the use of a qualified-id in the declaration of a (member) function:
When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers [...]"
Therefore any virtual void X::foo(); is illegal as a declaration inside C.
The code
class C : public A, public B
{
virtual void foo();
};
is the only way AFAIK to override foo, and it will override both A::foo and B::foo. There is no way to have two different overrides for A::foo and B::foo with different behaviour other than by introducing another layer of inheritance:
#include <iostream>
struct A
{
virtual void foo() = 0;
};
struct B
{
virtual void foo() = 0;
};
struct CA : A
{
virtual void foo() { std::cout << "A" << std::endl; }
};
struct CB : B
{
virtual void foo() { std::cout << "B" << std::endl; }
};
struct C : CA, CB {};
int main() {
C c;
//c.foo(); // ambiguous
A& a = c;
a.foo();
B& b = c;
b.foo();
}
You've got just one virtual function foo:
class A {
virtual void foo() = 0;
};
class B {
virtual void foo() = 0;
};
class C : public A, public B {
virtual void foo();
};
void C::foo(){}
void C::A::foo(){}
void C::B::foo(){};
int main() {
C c;
return 0;
}
I stepped into the same problem and accidentially opened a second thread. Sorry for that. One way that worked for me was to solve it without multiple inheritance.
#include <stdio.h>
class A
{
public:
virtual void foo(void) = 0;
};
class B
{
public:
virtual void foo(void) = 0;
};
class C
{
class IA: public A
{
virtual void foo(void)
{
printf("IA::foo()\r\n");
}
};
class IB: public B
{
virtual void foo(void)
{
printf("IB::foo()\r\n");
}
};
IA m_A;
IB m_B;
public:
A* GetA(void)
{
return(&m_A);
}
B* GetB(void)
{
return(&m_B);
}
};
The trick is to define classes derived from the interfaces (A and B) as local classes (IA and IB) instead of using multiple inheritance. Furthermore this approach also opens the option to have multiple realizations of each interface if desired which would not be possible using multiple inheritance.
The local classes IA and IB can be easily given access to class C, so the implementations of both interfaces IA and IB can share data.
Access of each interface can be done as follows:
main()
{
C test;
test.GetA()->foo();
test.GetB()->foo();
}
... and there is no ambiguity regarding the foo method any more.
You can resolve this ambiguity with different function parameters.
In real-world code, such virtual functions do something, so they usually already have either:
different parameters in A and B, or
different return values in A and B that you can turn into [out] parameters for the sake of solving this inheritance problem; otherwise
you need to add some tag parameters, which the optimizer will throw away.
(In my own code I usually find myself in case (1), sometimes in (2), never so far in (3).)
Your example is case (3) and would look like this:
class A
{
public:
struct tag_a { };
virtual void foo(tag_a) = 0;
};
class B
{
public:
struct tag_b { };
virtual void foo(tag_b) = 0;
};
class C : public A, public B
{
void foo(tag_a) override;
void foo(tag_b) override;
};
A slight improvement over adigostin's solution:
#include <iostream>
struct A {
virtual void foo() = 0;
};
struct B {
virtual void foo() = 0;
};
template <class T> struct Tagger : T {
struct tag {};
void foo() final { foo({}); }
virtual void foo(tag) = 0;
};
using A2 = Tagger<A>;
using B2 = Tagger<B>;
struct C : public A2, public B2 {
void foo(A2::tag) override { std::cout << "A" << std::endl; }
void foo(B2::tag) override { std::cout << "B" << std::endl; }
};
int main() {
C c;
A* pa = &c;
B* pb = &c;
pa->foo(); // A
pb->foo(); // B
return 0;
}
Assuming that the base classes A and B are given and cannot be modified.

How to refer derived class in template member?

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);
}

Class reference another two classes

I have two classes with some methods with same name.
Can I create third class that accept reference from ony of the other two and in the constructor to set obj variable to A or B type?
class A
{
public:
A();
void f();
};
class B
{
public:
B();
void f();
};
class C
{
public:
C(B&);
C(A&);
??? obj;
};
Maybe you want a template class:
template <typename T>
class C
{
T& obj;
public:
explicit C(T& t) : obj(t) {}
void f() { obj.f(); }
};
And then:
A a;
B b;
C<A> c1(a);
C<B> c2(b);
c1.f();
c2.f();
C++ is a very flexible language and as such provides multiple options for what you are asking for. Each with their own pros and cons.
The first route that comes to mind is to use polymorphism.
You have two routes to choose from: static or dynamic polymorphism.
The Static Polymorphic Route
To use static polymorphism (also known as compile-time polymorphism) you should make C a template class:
template <typename T> class C
{
public:
C(T&);
T& obj;
}
The Dynamic Polymorphic Route
To use dynamic (also known as run-time polymorphism) you should provide an interface:
class Fer
{
public:
virtual ~Fer() {}
virtual void f() = 0;
}
Which A and B would implement:
class A : public Fer
{
public:
A();
void f() overide;
};
class B : public Fer
{
public:
B();
void f() overide;
};
C would then be like this:
class C
{
public:
C(Fer&);
Fer& obj;
}
The Variant Route
There are various libraries that provide classes that can safely hold arbitrary types.
Some examples of these are:
Boost.Any
Boost.Variant
QVariant from Qt
When using such classes you generally need some means of converting back to the actual type before operating on it.
You can have a base class that defines the required interface.
class Base
{
public:
Base();
virtual void f();
};
And you can have derived classes that implement the interface.
class A : public Base
{
public:
A();
virtual void f();
};
class B : public Base
{
public:
B();
virtual void f();
};
The class C then refers to the Base class and can actually accept objects of A or B type.
class C
{
private:
Base& base;
public:
C(Base& b) : base(b) {}
};
It can be easily used then.
int main()
{
B b;
C c(b);
return 0;
}

C++ multiple inheritance with base classes deriving from the same class

I have stumbled on a problem while trying to re-use code from different classes. I post it here in hope that some of you might be able to help me.
I have a set of classes (B,C) deriving from the same class (A) which forces the implementation of some methods (foo, run). Class B implements these method, and both B and C provide other methods:
#include<iostream>
template<class I, class O>
class A {
public:
A() {}
virtual ~A() {}
virtual void foo() const = 0; // force implementation of this function
virtual void run() const = 0; // force implementation of this function
};
template<class I, class O>
class B : public A<I,O> {
public:
B() {}
virtual ~B() {}
virtual void foo() const { // implementation for the Base class
std::cout << "B's implementation of foo" << std::endl;
}
virtual void run() const { // implementation for the Base class
std::cout << "B's implementation of run" << std::endl;
}
virtual void foobar() const { // some other function provided by this class
std::cout << "B's implementation of foobar" << std::endl;
}
};
template<class I, class O, class M>
class C : public A<I,O> {
public:
C() {}
virtual ~C() {}
virtual void bar(M m) const { // some other function provided by this class
std::cout << "C's implementation of bar with: " << m << std::endl;
}
};
Now, what I am trying to do is inherit from both B and C so that I can have the extra methods (foobar, bar), but also not have to implement the method from class A (foo) because it is already defined in B:
template<class I, class O>
class D : public B<I,O>, public C<I,O,int> {
public:
D() {}
void run() const {
this->bar(123);
this->foo();
this->foobar();
}
};
But for some reason the compiler gives me this error:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:68:35: error: cannot allocate an object of abstract type ‘D<float, double>’
A<float, double> *d = new D<float, double>(); // what I need to do
test.cpp:48:11: note: because the following virtual functions are pure within ‘D<float, double>’:
class D : public B<I,O>, public C<I,O,int> {
^
test.cpp:9:22: note: void A<I, O>::foo() const [with I = float; O = double]
virtual void foo() const = 0; // force implementation of this function
This is the code I use to run it:
int main(int argc, char **argv)
{
A<float, double> *b = new B<float, double>();
b->foo(); // prints "B's implementation of foo"
b->run(); // prints "B's implementation of run"
//A<float, double> *c = new C<float, double, int>(); // obviously fails because C does not implement any of A's functions
//A<float, double> *d = new D<float, double>; // line 68: what I need to do
//d->run(); // ***throws the abstract class error
return 0;
}
I want to use the 'run' function of an object of class D from a pointer to a A. As all the functions are virtual I expect to execute implementation of each function defined in the lowest inheritance point, meaning that 'B::run' will be discarded. As 'D::run' uses functions from both B and C I need to inherit from both classes.
I hope I have described it enough and not confused anybody.
Thanks for the help!
If you change B and C to virtually inherit from the A template class, they will share a single base instance when combined by D and this error will go away:
template<class I, class O>
class B : virtual public A<I,O> {
// ...
template<class I, class O, class M>
class C : virtual public A<I,O> {
However, this pattern (known as the diamond inheritance (anti-)pattern) can be very difficult to reason about and I would strongly suggest avoiding it if possible. You are likely to run into even more obscure problems later.
Here is a sample of this technique working, but showing some results that may not be expected at first glance:
class A {
public:
virtual void foo() = 0;
};
class B : virtual public A {
public:
virtual void foo() override;
};
void B::foo()
{
std::cout << "B::foo()" << std::endl;
}
class C : virtual public A { };
class D : public B, public C { };
int main() {
D d;
C & c = d;
c.foo();
return 0;
}
Note that even though you are calling C::foo(), which is pure virtual, since there is only one A instance the inherited pure virtual function resolves to B::foo() though the shared A vtable. This is a somewhat surprising side-effect -- that you can wind up invoking methods implemented on a cousin type.
The answer by #cdhowie gives you a solution.
To understand the problem the compiler is complaining about, take a set of simpler classes:
struct A
{
virtual void foo() = 0;
};
struct B : A
{
virtual void foo() {}
}
struct C : A
{
void bar() {}
}
struct D : B, C
{
};
The class hierarchy of D is:
A A
| |
B C
\ /
D
With this inheritance structure, D has two virtual tables, one corresponding to the B inheritance hierarchy and one corresponding to C inheritance hierarchy. The difference being that in the B hierarchy, there is an implementation of A::foo() while there isn't one in the C hierarchy.
Let's say you were allowed to construct an object of type D.
D d;
C* cp = &d;
Now cp points to the C hierarchy of D, and uses a virtual table in which foo is not implemented. That will be a run time error that the compiler is helping you avoid at compile time.
I know this is a late answer but since you are deriving from a pure virtual function for class C, you have to implement it, then in those functions you call the base class:
virtual void foo() const { // for class C
B::foo();
}

Injecting an implementation into a class in C++

Consider the following example:
class A{
public: virtual void hello() = 0;
};
class B: public A{};
class C {
public: void hello(){
cout<<"Hi";
}
};
class D: public B, public C{};
The idea is that I would like to inject the implementation of hello into D through C. This doesn't seem to work unless I make C inherit from A too. Since that leads to diamond inheritance, I end up using virtual inheritance.
Is there any alternative to forcing an implementation into a derived class, without disturbing the abstract classes A and B here?
EDIT: I want a solution where I don't need to explicitly write code within D. This is because, I have many classes like D having the same implementation, which is exactly why I would like to push that implementation up to some class from which all of them inherit.
You can rewrite C as a template class that inherits from it's template argument and then derive D from C.
template <class Base>
class C : public Base {
public: void hello(){
cout<<"Hi";
}
};
class D: public C<B> {};
You can consider static inheritance/ policy classes when you need to inject an outside method into a class hierarchy. Note that injecting the method usually means that the method does not have the same name as an existing virtual in the class hierarchy (if it does, you are forced to use virtual inheritance or explicitly call with the scope :: or insert it in the class hierarchy). I called the method externalHello here.
The other options work fine as well but they conceptually point more to the fact that the injected method is not really an abstract method that could be used outside of this class hierarchy but should have been part of it in the first place.
class A
{
public:
virtual void hello() = 0;
};
class B: public A
{
public:
void hello()
{
cout<<"Hi from B" << endl;
};
};
template<typename T> class C1
{
public:
void injectedMethodUnrelatedToClassHierarchy()
{
cout<<"Hi from C1 with unrelated method" << endl;
};
void externalHello()
{
static_cast<T*>(this)->hello(); // will still call hello in B
injectedMethodUnrelatedToClassHierarchy(); // this will call hello here
};
};
class D: public B, public C1<D>{};
With client code:
D dx;
dx.hello();
dx.externalHello();
dx.injectedMethodUnrelatedToClassHierarchy();
It may work
#include<iostream>
using namespace std;
class A
{
public:
virtual void hello() = 0;
};
class C {
public: void hello(){
cout<<"Hi\n";
}
};
template<typename T>
class B: public A, public T
{
public:
void hello() override{ //override A::hello()
//do other staff
T::hello(); // call C::hello()
}
};
class D: public B<C>{
};
int main()
{
D d;
d.hello();
return 0;
}