3 ms·
This is a good overview of the ways to deal with this in C++. However, I often run into situations in large code bases with deep inheritance heirarchies where c
by SeanBoocock 9y ago
This is a good overview of the ways to deal with this in C++. However, I often run into situations in large code bases with deep inheritance heirarchies where calling Super::Foo() on virtual methods is necessary for correct functionality and a frequent source of bugs.
To the extent that I have control over the architecture, I prefer flat hierarchies with pure virtuals and final implementations, but what are good approaches to solving this issue for deeper class hierarchies? Is there a good alternative to the pseudo Super if Class A, B, C, and D each need to twiddle some state when you call ::Foo() on an object of type E?
- Waterluvian 9y agoPersonally I have yet to find a real-world practical example of a deep hierarchy that felt like an intuitive, natural approach to solving the given problem. I'm not specifically skeptical of their existence, but I do question if maybe the problem with deep hierarchies is addressed by not using them.
- katastic 9y agoIn D, I just call super.this(var, var) to ensure I'm calling the correct base constructor. And fire off an assert if super(void) gets called because I didn't explicitly write a specialized one. But I think C++ has what... parameter lists for that?
- SeanBoocock 9y agoOh I quite agree that in general having a deep inheritance hierarchy is not ideal and that many problems can better be solved with compartmentalization or other approaches. I was asking more in the context of you have a million+ line code base and want to make things less error prone/cleaner without refactoring large chunks of it.
- sounds 9y agoThough this is not the only solution, a visitor pattern seems to match. I can think of other possibilities; hopefully this sparks some good ideas for you. I'll sketch up how I think the visitor pattern could work, sorry if it's already obvious: Base class A. Derived classes B, C, and D. When A::Foo() is called run code from each class, in the order they are initialized. class A { protected: vector<function<void(int)>> visitFoo; public: void Foo(int bar) { for (auto fn : visitFoo) { fn(bar); } } }; class B : public A { protected: // Do not override Foo in class B, C, or D. void FooB(int bar) { } public: B() { // visitor pattern visitFoo.emplace_back(FooB); } }; Repeat for C and D.