Code:
struct A{
const bool const_some_write_once_flag;
A(): const_some_write_once_flag(false) { }
};
struct B: public A{
B(): const_some_write_once_flag(true) { }
};
the error is: class ‘B’ does not have any field named ‘const_some_write_once_flag’. I believe that it's because while being in the constructor of B, the object being created is not yet of type A, because the "inherited slice" of A has not yet been initialized.
I've tried several workarounds with no luck, and I'll omit them here. Is there a way to achieve what I'm trying to do?
In its initializer list,B can only initialize its own data members, its direct base classes, and any virtual base classes. const_some_write_once_flag is none of these; it is a data member of A. It can only be initialized by a constructor of A.
struct A{
const bool const_some_write_once_flag;
A(): const_some_write_once_flag(false) { }
protected:
A(bool flag) : const_some_write_once_flag(flag) { }
};
struct B: public A{
B(): A(true) { }
};
The following achieves nearly what you're trying to do. It does create a protected member of A that any other class that chooses to inherit from A can use, though. You could be even more protective and make B a friend of A and then make the constructor that takes a parameter private.
class A{
public:
const bool const_some_write_once_flag;
A(): const_some_write_once_flag(false) { }
protected:
A( const bool initialValue ): const_some_write_once_flag( initialValue ) {}
};
class B: public A{
public:
B(): A(true) { }
};
Related
Why can't I do this?
class A
{
public:
int a, b;
};
class B : public A
{
B() : A(), a(0), b(0)
{
}
};
You can't initialize a and b in B because they are not members of B. They are members of A, therefore only A can initialize them. You can make them public, then do assignment in B, but that is not a recommended option since it would destroy encapsulation. Instead, create a constructor in A to allow B (or any subclass of A) to initialize them:
class A
{
protected:
A(int a, int b) : a(a), b(b) {} // Accessible to derived classes
// Change "protected" to "public" to allow others to instantiate A.
private:
int a, b; // Keep these variables private in A
};
class B : public A
{
public:
B() : A(0, 0) // Calls A's constructor, initializing a and b in A to 0.
{
}
};
Leaving aside the fact that they are private, since a and b are members of A, they are meant to be initialized by A's constructors, not by some other class's constructors (derived or not).
Try:
class A
{
int a, b;
protected: // or public:
A(int a, int b): a(a), b(b) {}
};
class B : public A
{
B() : A(0, 0) {}
};
Somehow, no one listed the simplest way:
class A
{
public:
int a, b;
};
class B : public A
{
B()
{
a = 0;
b = 0;
}
};
You can't access base members in the initializer list, but the constructor itself, just as any other member method, may access public and protected members of the base class.
# include<stdio.h>
# include<iostream>
# include<conio.h>
using namespace std;
class Base{
public:
Base(int i, float f, double d): i(i), f(f), d(d)
{
}
virtual void Show()=0;
protected:
int i;
float f;
double d;
};
class Derived: public Base{
public:
Derived(int i, float f, double d): Base( i, f, d)
{
}
void Show()
{
cout<< "int i = "<<i<<endl<<"float f = "<<f<<endl <<"double d = "<<d<<endl;
}
};
int main(){
Base * b = new Derived(10, 1.2, 3.89);
b->Show();
return 0;
}
It's a working example in case you want to initialize the Base class data members present in the Derived class object, whereas you want to push these values interfacing via Derived class constructor call.
Why can't you do it? Because the language doesn't allow you to initializa a base class' members in the derived class' initializer list.
How can you get this done? Like this:
class A
{
public:
A(int a, int b) : a_(a), b_(b) {};
int a_, b_;
};
class B : public A
{
public:
B() : A(0,0)
{
}
};
While this is usefull in rare cases (if that was not the case, the language would've allowed it directly), take a look at the Base from Member idiom. It's not a code free solution, you'd have to add an extra layer of inheritance, but it gets the job done. To avoid boilerplate code you could use boost's implementation
Aggregate classes, like A in your example(*), must have their members public, and have no user-defined constructors. They are intialized with initializer list, e.g. A a {0,0}; or in your case B() : A({0,0}){}. The members of base aggregate class cannot be individually initialized in the constructor of the derived class.
(*) To be precise, as it was correctly mentioned, original class A is not an aggregate due to private non-static members
I have a class A and two children B and C as follows:
class A {
private:
int x;
template<class T>
void setX(T &y);
public:
A();
};
class B : public A {
private:
static const double y;
public:
B();
};
class C : public A {
private:
static const int y;
public:
C();
};
Both children only differ in the type of their static member y. The implementation of both C and B is the same except on the initialization of the static member:
B::B() : y (1.2) { setX(y) }
C::C() : y (2) { setX(y) }
But the problem with this approach is that in the implementation file I have to write twice the same code for B and C. Is there a proper way to write this such that I do not need to write twice the call to setX?
In the real problem the classes are a little more complicated, but the situation at hand is the same. In particular, initialization of y requires non-trivial constructors and so it has to be in the implementation file.
You can write a constructor for A as a function template.
class A {
//....
public:
template<typename T>
explicit A(T& y) {
setX(y);
}
};
And call that constructor from child classes:
class B : public A{
//...
public:
B() : A(1.2), y(1.2)
{}
};
Only problem is that base class constructor gets called first, so you need to repeat constant data value twice. You can easily macro it though.
Here is a skeleton code:
class C{
callMe(){}
};
class A{
// How to use callMe()
};
class B : C {
callMe();
A a;
};
In this example class B extends class C, so it can call callMe() method. But I need to use callMe() using class A given that class A can not extend class C. I wonder how?
you need to make A contain an object of type C.
class A
{
private:
C objC;
public:
void WhateverMethod() { objC.CallMe(); }
};
Also, the syntax for inheritance is
class B : C{
};
If you want B to simply have access to CallMe(), then you do not need to redefine it in B. It will inherit it from C. If you want B to override CallMe then you need to do this:
class C
{
public:
virtual void CallMe() { //definition }
};
class B : public C
{
public:
void CallMe() { //redefine it here }
};
Note, I assume from your syntax errors that you are a JAVA programmer. Methods are not automatically marked as virtual in C++, you have to mark them as virtual if you want to use polymorphism, and you have to use them from a pointer for it to work.
class C{
callMe(){}
friend class A;
};
class A{
//use call me here
};
You need to provide an instance of C:
class C {
public: // has to be public
void callMe() const {}
};
class A{
public:
A(const C& inst) : inst(inst) {}
void foo() {
inst.callMe();
}
private:
const C& inst;
};
I have a class A which has a private method called a(). I have also a class B which needs to access a() (but just B should have access to a(), thats why a() is private). I could now use a friend specifier but that would make other private methods of A (lets call them b() and c()) also available to B and I dont want that behaviour.
Is there a way to make just a() of A accessable to B?
There is a way -- if your class has a public template function:
class A {
// apparently private
void priv () { std::cout << "got you A::a()" << std::endl ; }
public:
template <class T>
void abuse() {}
};
struct Thief {};
template <>
void A::abuse<Thief>() {
this->priv();
}
int main() {
A a;
// obviously do not compile : a.priv();
// this i OK
a.abuse<Thief>();
return 0;
}
I must confess I stole this from GotW...
No there's not, but as you specify the precise class, just B could access A's private members.
You just have to take care of what method are called.
As friend relationship are not inherited, you don't have to worry about B's possible subclasses.
This could be done with some "twist".
Just factor out method a() from A class into a parent class that has B as a friend class, then let A inherit it. this will leave a() as being a method in A, but the only private method accessible by its parent's friend B.
here is a very simple code to clarify what I've said:
class parent
{
friend class B;
private:
void a() {}
};
class A:public parent
{
private:
void b() {}
void c() {}
};
class B
{
A* m_a;
public :
B()
{
m_a = new A();
m_a->a(); // OK
m_a->b(); // error C2248: 'A::b' : cannot access private member declared in class 'A'
}
};
hope it helps !
Yes, I have an easy way. Let B have a pointer of A::a(), like this:
typedef boost::function<void ()> functype;
class A {
private:
void a();
};
class B {
public:
void setfp(functype f) {m_f = f;}
void foo() {
// do some stuff
m_f();
}
private:
functype m_f;
};
A a;
B b;
b.setfp(boost::bind(&A::a, &a));
b.foo();
Why I can't access base class A's a member in class B initialization list?
class A
{
public:
explicit A(int a1):a(a1)
{
}
explicit A()
{
}
public:
int a;
public:
virtual int GetA()
{
return a;
}
};
class B : public A
{
public:
explicit B(int a1):a(a1) // wrong!, I have to write a = a1 in {}. or use A(a1)
{
}
int GetA()
{
return a+1;
}
};
class C : public A
{
public:
explicit C(int a1):a(a1)
{
}
int GetA()
{
return a-1;
}
};
A's constructor runs before B's, and, implicitly or explicitly, the former construct all of A's instance, including the a member. Therefore B cannot use a constructor on a, because that field is already constructed. The notation you're trying to use indicates exactly to use a constructor on a, and at that point it's just impossible.
To build on Alex' answer, you can initialize the base class' "a" member by controlling its construction, like so:
class B : public A
{
public:
explicit B(int a1) : A(a1) { } // This initializes your inherited "a"
...
};
Note that I'm constructing the base class (capital "A") above, rather than attempting to directly initialize its inherited member (lowercase "a", drawing from your example).
To build even further on pilcrow's answer, you could easily initialize the A member like you want by overriding it in your B class:
class B : public A
{
public:
int a; // override a
explicit B(int a1) : a(a1) // works now
{
}
...
};
Though, I wouldn't necessarily recommend this ;)