C++ static const members overriding - c++

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?

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
}

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

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.

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.

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

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.

Related

Is it possible to pass a struct's member variable as parameter

I am trying to associate a struct's member variable with a class. So that when I create a new class, I can specify that it is associated with this member variable in a struct. For example:
struct A {
int a;
int b;
};
static A a[2];
a[0].a = 1;
a[0].b = 2;
a[1].a = 3;
a[1].b = 4;
class foo {
public:
foo(int index, ???) {
c = a[index].???; //Is it possible to define the 2nd parameter as a getter of struct A's member? So this line could resolve to either a[index].a or a[index].b?
}
private:
int c;
};
So that:
new foo(0, ???) would set c to 1 given ??? refer to A::a
new foo(0, ???) would set c to 2 given ??? refer to A::b
new foo(1, ???) would set c to 3 given ??? refer to A::a
new foo(1, ???) would set c to 4 given ??? refer to A::b
Yes, it is possible, you need to pass a data member pointer:
#include <iostream>
struct A
{
int a;
int b;
};
static A a[2]
{
1, 2
, 3, 4
};
class foo
{
public: int c;
public:
foo(int const index, int A::* const p_field)
{
c = a[index].*p_field;
}
};
int main()
{
foo const f1(0, &A::a);
::std::cout << f1.c << ::std::endl;
foo const f2(0, &A::b);
::std::cout << f2.c << ::std::endl;
foo const f3(1, &A::a);
::std::cout << f3.c << ::std::endl;
foo const f4(1, &A::b);
::std::cout << f4.c << ::std::endl;
return 0;
}
Check this code at online compiler
You have a couple options. If you just want the integer (like you have in your code you've posted), then just take an integer as a parameter to the constructor and pass it the right number.
class foo {
public:
foo(int val) {
c = val
}
private:
int c;
};
int main() {
foo f(a[0].b);
}
Or you could take a reference to an integer. This way if one changes, the other will as well:
class foo {
public:
foo(int &val) : c(val) { } //need to use an initialization list for this one
private:
int &c;
};
int main() {
foo f(a[0].b);
a[0].b = -1; //f.c will be -1 now as well
}
Using a data member pointer as in VTT's answer is the most direct solution but I often find member pointers and member function pointer syntax a bit cumbersome and I believe it is hard for the compiler to optimize.
For these kind of things I prefer to use a stateless lambda. You can pass a lambda to a function template and then the compiler can easily optimize it away:
#include <iostream>
struct A {
int a;
int b;
};
static A a[2]{{1, 2}, {3, 4}};
class foo {
public:
int c;
public:
template<typename F>
foo(int index, F getter) { c = getter(a[index]); }
};
int main() {
auto agetter = [](const A& a){ return a.a; };
auto bgetter = [](const A& a){ return a.b; };
foo const f1(0, agetter);
std::cout << f1.c << "\n";
foo const f2(0, bgetter);
std::cout << f2.c << "\n";
foo const f3(1, agetter);
std::cout << f3.c << "\n";
foo const f4(1, bgetter);
std::cout << f4.c << "\n";
}

Redefine a constant member variable in inherited class

Say I wish to define a member variable in a parent class and set its value in an inherited class. Perhaps these identify functionality available in the class or the nature of the child class. For example:
class A
{
public:
inline int getX() { return x; }
protected:
const int x = 0;
};
class B : public A
{
protected:
const int x = 10;
};
class C : public A
{
protected:
const int x = 50;
};
It should go without saying that scope issues will prevent the above from working properly. However, is there a way to make this work as intended?
Since the variable is meant to identify the nature of the inherited classes, I would prefer if it were const - this problem would not arise if it were not const and merely redefined in the constructor, so far as I can tell.
While fiddling with the compiler trying to make sure my example code made sense, I actually came across the fact that the way I was attempting to define the constants was C++11-specific. That led me to look into the ways it was done before, and I found this question, which shed some light on the matter indirectly.
Defining a variable in this way should be done by having the base class take an argument in its constructor, in the form of:
class A
{
public:
A( const int& type ) : x(type) {}
inline int getX() { return x; }
protected:
const int x;
};
class B : public A
{
public:
B() : A(10) {}
};
class C : public A
{
public:
C() : A(50) {}
};
This will work as intended and allow the constant x to be redefined by inherited classes.
To demonstrate the point I made in my comment, here is an example of what I think you're trying to do (deduced from comments).
I have provided both duck-typed and polymorphic solutions in the same program with a timed run through each.
I use 10 million samples of each to eliminate memory cache noise.
You will notice that the run time of the polymorphic solution is significantly less than that of the duck-typed solution.
#ifdef _WIN32
#include <Windows.h>
double get_cpu_time(){
FILETIME a,b,c,d;
if (GetProcessTimes(GetCurrentProcess(),&a,&b,&c,&d) != 0){
// Returns total user time.
// Can be tweaked to include kernel times as well.
return
(double)(d.dwLowDateTime |
((unsigned long long)d.dwHighDateTime << 32)) * 0.0000001;
}else{
// Handle error
return 0;
}
}
#else
#include <sys/time.h>
inline double get_cpu_time() noexcept {
return (double)clock() / CLOCKS_PER_SEC;
}
#endif
#include <iostream>
#include <vector>
#include <memory>
struct A
{
A(bool copy_) : copy{copy_} {}
virtual ~A() = default;
const bool copy = false;
};
struct RealA : public A
{
RealA() : A { false } {}
};
struct CopyA : public A
{
CopyA() : A { true } {}
};
// A Thing holder will hold any object which has an interface supports do_something_to(T& thing)
struct AHolder {
template<class Thing>
AHolder(std::unique_ptr<Thing> ptr)
: _ptr { std::move(ptr) }
{
}
template<class Thing, class...Args>
static AHolder construct(Args&&...args)
{
return AHolder { std::make_unique<model<Thing>>(std::forward<Args>(args)...) };
}
void do_something() const {
_ptr->do_something();
}
private:
struct concept {
virtual ~concept() = default;
virtual void do_something() = 0;
};
template<class Thing> struct model : concept {
template<class...Args>
model(Args&&...args) : _thing { std::forward<Args>(args)... } {}
private:
void do_something() override {
do_something_to(_thing);
}
Thing _thing;
};
std::unique_ptr<concept> _ptr;
};
using namespace std;
size_t copies_processed = 0;
size_t reals_processed = 0;
void do_something_to(const CopyA&)
{
// simulate work
++copies_processed;
}
void do_something_to(const RealA&)
{
// simulate work
++reals_processed;
}
int main(int argc, char **argv) {
std::vector<std::unique_ptr<A>> duck_typing;
std::vector<AHolder> polymorphic;
constexpr size_t samples = 10000000;
for (size_t i = 0 ; i < samples ; ++i) {
if (i % 2) {
duck_typing.push_back(make_unique<RealA>());
polymorphic.emplace_back(AHolder::construct<RealA>());
}
else {
duck_typing.push_back(make_unique<CopyA>());
polymorphic.emplace_back(AHolder::construct<CopyA>());
}
}
auto duck_start = get_cpu_time();
// nasty duck-typing solution
for (const auto& ptr : duck_typing) {
if (ptr->copy) {
do_something_to(*(static_cast<CopyA*>(ptr.get())));
}
else {
do_something_to(*(static_cast<RealA*>(ptr.get())));
}
}
auto duck_stop = get_cpu_time();
auto poly_start = get_cpu_time();
for (const auto& a_like : polymorphic) {
a_like.do_something();
}
auto poly_stop = get_cpu_time();
cout << "duck typing : " << duck_stop - duck_start << endl;
cout << "polymorphic : " << poly_stop - poly_start << endl;
cout << "copies processed : " << copies_processed << endl;
cout << "reals processed : " << reals_processed << endl;
return 0;
}
sample output :
duck typing : 0.162985
polymorphic : 0.137561
copies processed : 10000000
reals processed : 10000000

How in C++ use templates to call specific members of supplied type

Lets assume we have two classes
struct A
{
int x = 1;
};
struct B
{
int y = 2;
};
I want to have template that will return value of member (in a case of A I want to return value of "x", in case of B I want to return value of "y").
Example call:
const auto myVariable = f<A>();
or
A a;
const auto myVariable = f<A>(a);
I don't want to have 2 template specializations - ideally it would be one template with some kind of "if statement", but maybe it is not possible?
It may be written with C++11 (but not with C++14).
Generally how you are using templates when you have such problems - quite big template and only in one or two places you need to take values from different members - which may be deduced based of type of that variable.
PROBLEM: unnecessary it is not allowed to modify classes A and B
Why use templates at all?
int f(const A& a) { return a.x; }
int f(const B& b) { return b.y; }
Just in case you ask for the template because you want to switch between A and B at compile time...and you have a reason not to simply typedef A or B directly...
struct A
{
int x;
};
struct B
{
int y;
};
struct A1 : public A { int Get() const { return x; } };
struct B1 : public B { int Get() const { return y; } };
// Begin possible shortcut avoiding the template below:
#ifdef USE_A
typedef A1 Bar;
#endif
#ifdef USE_B
typedef B1 Bar;
#endif
// End possible shortcut.
template <class _Base>
struct CompileTimeAOrB
: public _Base
{
int Get() const
{
return _Base::Get();
}
};
#define USE_A
//#define USE_B
#ifdef USE_A
typedef CompileTimeAOrB<A1> Foo;
#endif
#ifdef USE_B
typedef CompileTimeAOrB<B1> Foo;
#endif
EDIT: Since A and B cannot be changed, introduced A1, B1 ;)
#include <iostream>
struct A
{
int value;
A() : value(2) {}
};
struct B
{
int value;
B() : value(4) {}
};
template <typename T>
int GetValue(T t)
{
return t.value;
}
int main()
{
A a;
B b;
std::cout << GetValue(a) << std::endl;
std::cout << GetValue(b) << std::endl;
return 0;
}
In order for it to work, you'd need to have the same variable or function named declared in each class you wanted this to work with.

How to set parent members when creating inherited struct in C++

I have a struct type A, which I could instantiate with A(p_a1, p_a2) and a struct type B, which inherits from A, that I can instantiate with B(p_b1, p_b2, p_b3).
Is there a standard way to create a B instance while also setting p_a1 and p_a2? Would I just set them after creating the B instance with b.p_a1 = v_a1; b.p_a2 = v_a2?
(Sorry for any incorrect use of terminology. I don't have much experience with C++.)
Thanks
You are looking for a C++ feature named constructor initialization lists. This example should clarify it to you:
#include <iostream>
class Foo
{
public:
Foo( int x )
{
std::cout << "Foo's constructor "
<< "called with "
<< x
<< std::endl;
}
};
class Bar : public Foo
{
public:
Bar(int x, int y, int z) : Foo( x ) // construct the Foo part of Bar
{
std::cout << "Bar's constructor" << std::endl;
}
};
int main()
{
Bar stool(10,11,12);
}
What you intend to do is achievable using initialization lists and can be done as follows:
struct A
{
A(int _a):a(_a){}
};
struct B : public A
{
B(int _a, int _b):A(a), b(_b){}
} ;
In the sample code which you have provided, what you are doing in these lines b.p_a1 = v_a1; b.p_a2 = v_a2 is called assignment. While the former will invoke just the right constructor, latter would invoke the default constructor.
Try the following
struct A {
int _a1;
int _a2;
A(int a1, int a2); //assume it is defined
};
struct B : public A {
int _b1;
B(int p1, int p2, int p3);
};
B(int p1, int p2, int p3)
: A(p1,p1), // <<== This is where parent member variables will be initialized.
_b1(p3) //or some other way to populate _b1
{ }
google "C++ constructor initialization list"

C++ : Initializing base class constant static variable with different value in derived class?

I have a base class A with a constant static variable a. I need that instances of class B have a different value for the static variable a. How could this be achieved, preferably with static initialization ?
class A {
public:
static const int a;
};
const int A::a = 1;
class B : public A {
// ???
// How to set *a* to a value specific to instances of class B ?
};
You can't. There is one instance of the static variable that is shared by all derived classes.
Static members are unique in the application. There is a single A::a constant in your system. What you can do is create a B::a static constant in B that will hide the A::a static (if you don't use the fully qualified name:
class A {
public:
static const int a = 10;
};
static const int A::a;
class B : public A {
public:
static const int a = 20;
static void test();
};
static const int B::a;
void B::test() {
std::cout << a << std::endl; // 20: B::a hides A::a
std::cout << A::a << std::endl; // 10: fully qualified
}
You can do this with Curiously recurring template pattern (you'll have to lose the const though).
template <typename T>
class A {
public:
static int a;
};
template <typename T>
int A<T>::a = 0;
class B : public A<B> {
struct helper { // change the value for A<B>::a
helper() { A<B>::a = 42; }
};
static helper h;
};
B::helper B::h;
May be we can try this way as below ::
The benefit of the below is that you don't have to write the code multiple times, but the actual generated code might be big.
#include <iostream>
using namespace std;
template <int t>
class Fighters {
protected :
static const double Fattack;
double Fhealth;
static const double Fdamage;
static int count;
public :
Fighters(double Fh) : Fhealth(Fh) { }
void FighterAttacked(double damage) {
Fhealth -= damage;
}
double getHealth()
{
return Fhealth;
}
static int getCount()
{
//cout << count << endl;
return count;
}
};
const double Fighters<1>::Fdamage = 200.0f;
const double Fighters<1>::Fattack = 0.6f;
int Fighters<1>::count = 0;
class Humans : public Fighters<1> {
public :
Humans(double Fh = 250) : Fighters<1>(Fh) { count++; }
};
const double Fighters<2>::Fdamage = 40.0f;
const double Fighters<2>::Fattack = 0.4f;
int Fighters<2>::count = 0;
class Skeletons : public Fighters<2> {
public :
Skeletons(double Fh = 50) : Fighters<2>(Fh) { count++; }
};
int main()
{
Humans h[100];
Skeletons s[300];
cout << Humans::getCount() << endl;
cout << Skeletons::getCount() << endl;
return 0;
}
This is part of my other code example .. don't mind many other data but concept can be seen.