Reputation: 1017
Consider the following.
struct A {
static const int X = 1;
static void printX() {std::cout << "X " << X << std::endl; };
};
struct B: public A {
static const int X = 2;
};
int main(argc argv){
B b;
b.printX();
}
How to force the b.printX()
to print value 2?
Both - constant and method - MUST be static. And therefore, virtual methods are not suitable.
For anyone who thinks they know my task better than me and wants to see me rethinking it, I'll explain the goal of my efforts :)
Just imagine class which has behaviour based on set of static constants. The simplest way to implement child class with different set of constants and therefore with different behaviour is derivation of class from previous one with specific set of constant values. It is possible to solve that task using virtual functions. Of cause possible, no question. But this solution will be not very pure in sense of accordance to a theory of modeled entities. Usage of virtual methods in this case will be more a trick than correct implementation.
For example, IR channels have different timing of pulse durations and package structure. It is convenient to define set of child classes (different IR channel implementations) with a specific set of constant values. That values are static because they are common for every object of class and const because they are needed at compile time only. And because internal implementations of base and child classes are slightly different the best relationship between of them are super class - child class
.
Is it rationale for my original question now?
Upvotes: 15
Views: 15918
Reputation: 1587
Why not using templates?
constexpr int nfo[]{ 0, 1, 2, 3 };
template <int N>
class Haha {
public:
const static int BOOM = nfo[ N ];
};
int main() {
std::cout << Haha<2>::BOOM << std::endl; // 2
}
Upvotes: 1
Reputation: 1803
Just make the value of X a template parameter:
#include <iostream>
template<int XValue=1>
struct A {
static const int X = XValue;
static void printX() {std::cout << "X " << X << std::endl; };
};
template<int XValue=2>
struct B: public A<XValue> {
};
struct C: public B<3> {
};
int main(int, char**){
B<> b;
b.printX();
}
Upvotes: 6
Reputation: 8304
Instead of using static
and template
, I would just use regular constant attributes and constructors.
For example:
#include <iostream>
struct A {
A(const char* fn, const int X) : filename(fn), X(X) {};
void print() { std::cout << "X = " << X << ", FN = " << filename << std::endl; };
protected:
const char* filename;
const int X;
};
struct B : public A {
B() : A("data.dat", 5) {};
};
int main(int, char **) {
B b;
b.print();
}
Functionally, it does exactly what you want. Output:
X = 5, FN = data.dat
— It's now the compiler's job to optimize those constants. And if you are not intending to use thousands of objects B
, it's probably not worth worrying about making those constants static
.
Upvotes: 3
Reputation: 17026
You are going to need a template, and to change the inheritance to use the template, as you will see. The trick is to make it work whether the derived class has an X to overshadow the base-class X or not.
template<class C>
struct A {
static const int X = 1;
template<typename T>
static int getX(decltype(T::X)*)
{ return T::X; }
template<typename T>
static void getX(...)
{ return X; }
static void printX()
{ std::cout << "X " << getX<C>(0) << std::endl; }
};
struct B: public A<B> {
static const int X = 2;
};
struct B2: public A<B2> {
// No X
};
int main(){
B b;
b.printX(); // Prints X 2
B2 b2;
b2.printX(); // Prints X 1
}
Upvotes: 9
Reputation: 10613
OK, I'll play along... you want to nest this more than one level deep. Fine.
#include <iostream>
template <int XX> struct T
{
static const int X = XX;
static void printX()
{
std::cout << "X=" << X << std::endl;
}
};
struct AA
{
static const int X = 1;
/* all other members go here */
};
struct A : public AA, public T<AA::X>
{
/* empty - put stuff in AA instead */
};
struct BB : public AA
{
static const int X = 2;
};
struct B : public BB, public T<BB::X>
{
};
struct CC : public BB
{
static const int X = 3;
};
struct C : public CC, public T<CC::X>
{
};
struct DD : public CC
{
static const int X = 4;
};
struct D : public DD, public T<DD::X>
{
};
int main(int, char **)
{
A a;
B b;
C c;
D d;
a.printX();
b.printX();
c.printX();
d.printX();
return 0;
}
You could even skip the static const int X = ...;
in every class, and just do public T<1>
, public T<2>
etc as necessary.
Upvotes: 0
Reputation: 10613
Short answer: you can't.
Slightly longer, more complex answer: Well, maybe you can. With templates!
#include <iostream>
template <typename T> struct A
{
static const int X = 1;
static void printX()
{
std::cout << "X=" << T::X << std::endl;
}
};
struct B : public A<B>
{
static const int X = 2;
};
int main(int, char **)
{
B b;
b.printX();
return 0;
}
Upvotes: 0
Reputation: 95509
By definition, anything you do with static members will be "overshadowing", not "overriding". You could reimplement "printX()" in "B", but you would not really be overriding the behavior; because this would use overshadowing, the behavior would depend entirely on the compile-time, not runtime, type.
Upvotes: 4