I have 2 classes which are very similar and I want to reduce code duplication by moving some functions to base class and inheriting from it.
The function has to process multiple arrays with different, compile-time known sizes.
How can it be done generically without using std::vector
?
I'd like to replace std::vector with std::array everywhere in this code example, because all the sizes are known in compile-time. I use base class only to reduce the code duplication, I don't really need polymorphism.
#include <vector>
#include <iostream>
class Base {
public:
Base(){}
virtual ~Base(){}
protected:
virtual std::vector<int>& GetA() = 0;
virtual std::vector<int>& GetB() = 0;
void Foo() {
for (const auto& el : GetA()) {
std::cout<<el;
}
for (const auto& el : GetB()) {
std::cout<<el;
}
}
};
class Impl1 : public Base {
public:
Impl1() : a_{1,2,3,4,5}, b_{12,13} {
Foo();
}
~Impl1() {}
private:
std::vector<int> a_;
std::vector<int> b_;
std::vector<int>& GetA() { return a_;}
std::vector<int>& GetB() { return b_;}
};
class Impl2 : public Base {
public:
Impl2() : a_{0}, b_{1,2,3,4,5} {
Foo();
}
~Impl2() {}
private:
std::vector<int> a_;
std::vector<int> b_;
std::vector<int>& GetA() { return a_;};
std::vector<int>& GetB() { return b_;}
};
If you want a base class just for code deduplication, it is recommended to avoid virtual
and use template
s instead. To tell users they should not use the base class, you can put it in namespace detail
.
Templates are also the way to parametrize std::array
size, as they can be used with values and not just types - in fact, that is exactly how std::array
is implemented.
Here is an example:
namespace detail {
template <size_t SizeA, size_t SizeB>
class Base {
public:
Base(const decltype(a)& a, const decltype(b)& b)
: a{a}, b{b} {}
void Foo() {
for (const auto& el : a) {
std::cout << el;
}
for (const auto& el : b) {
std::cout << el;
}
}
private: // or protected, as you wish
std::array<int, SizeA> a{};
std::array<int, SizeB> b{};
};
}
class Impl1 : public detail::Base<5, 2> {
public:
Impl1() : detail::Base{{1,2,3,4,5}, {12,13}}
{
Foo();
}
};
class Impl2 : public detail::Base<1, 5> {
public:
Impl2() : detail::Base{{0}, {1,2,3,4,5}}
{
Foo();
}
};