I ran into an error yesterday and, while it's easy to get around, I wanted to make sure that I'm understanding C++ right.
I have a base class with a protected member:
class Base
{
protected:
int b;
public:
void DoSomething(const Base& that)
{
b+=that.b;
}
};
This compiles and works just fine. Now I extend Base but still want to use b:
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b+=that.b;
d=0;
}
};
Note that in this case DoSomething is still taking a reference to a Base, not Derived. I would expect that I can still have access to that.b inside of Derived, but I get a cannot access protected member error (MSVC 8.0 - haven't tried gcc yet).
Obviously, adding a public getter on b solved the problem, but I was wondering why I couldn't have access directly to b. I though that when you use public inheritance the protected variables are still visible to the derived class.
A class can only access protected members of instances of this class or a derived class. It cannot access protected members of instances of a parent class or cousin class.
In your case, the Derived class can only access the b protected member of Derived instances, not that of Base instances.
Changing the constructor to take a Derived instance will solve the problem.
protected members can be accessed:
through this pointer
or to the same type protected members even if declared in base
or from friend classes, functions
To solve your case you can use one of last two options.
Accept Derived in Derived::DoSomething or declare Derived friend to Base:
class Derived;
class Base
{
friend class Derived;
protected:
int b;
public:
void DoSomething(const Base& that)
{
b+=that.b;
}
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b+=that.b;
d=0;
}
};
You may also consider public getters in some cases.
As mentioned, it's just the way the language works.
Another solution is to exploit the inheritance and pass to the parent method:
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
Base::DoSomething(that);
d=0;
}
};
You have access to the protected members of Derived, but not those of Base (even if the only reason it's a protected member of Derived is because it's inherited from Base)
You can try with static_cast< const Derived*>(pBase)->Base::protected_member ...
class Base
{
protected:
int b;
public:
...
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b += static_cast<const Derived*>(&that)->Base::b;
d=0;
}
void DoSomething(const Base* that)
{
b += static_cast<const Derived*>(that)->Base::b;
d=0;
}
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething()
{
b+=this->b;
d=0;
}
};
//this will work
Following the hack for stl I wrote a small code which seems to solve the problem of accessing the protected members in derived class
#include <iostream>
class B
{
protected:
int a;
public:
void dosmth()
{
a = 4;
}
void print() {std::cout<<"a="<<a<<std::endl;}
};
class D: private B
{
public:
void dosmth(B &b)
{
b.*&D::a = 5;
}
};
int main(int argc, const char * argv[]) {
B b;
D d;
b.dosmth();
b.print();
d.dosmth(b);
b.print();
return 0;
}
Prints
a=4
a=5
Use this pointer to access protected members
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
this->b+=that.b;
d=0;
}
};
Related
I ran into an error yesterday and, while it's easy to get around, I wanted to make sure that I'm understanding C++ right.
I have a base class with a protected member:
class Base
{
protected:
int b;
public:
void DoSomething(const Base& that)
{
b+=that.b;
}
};
This compiles and works just fine. Now I extend Base but still want to use b:
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b+=that.b;
d=0;
}
};
Note that in this case DoSomething is still taking a reference to a Base, not Derived. I would expect that I can still have access to that.b inside of Derived, but I get a cannot access protected member error (MSVC 8.0 - haven't tried gcc yet).
Obviously, adding a public getter on b solved the problem, but I was wondering why I couldn't have access directly to b. I though that when you use public inheritance the protected variables are still visible to the derived class.
A class can only access protected members of instances of this class or a derived class. It cannot access protected members of instances of a parent class or cousin class.
In your case, the Derived class can only access the b protected member of Derived instances, not that of Base instances.
Changing the constructor to take a Derived instance will solve the problem.
protected members can be accessed:
through this pointer
or to the same type protected members even if declared in base
or from friend classes, functions
To solve your case you can use one of last two options.
Accept Derived in Derived::DoSomething or declare Derived friend to Base:
class Derived;
class Base
{
friend class Derived;
protected:
int b;
public:
void DoSomething(const Base& that)
{
b+=that.b;
}
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b+=that.b;
d=0;
}
};
You may also consider public getters in some cases.
As mentioned, it's just the way the language works.
Another solution is to exploit the inheritance and pass to the parent method:
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
Base::DoSomething(that);
d=0;
}
};
You have access to the protected members of Derived, but not those of Base (even if the only reason it's a protected member of Derived is because it's inherited from Base)
You can try with static_cast< const Derived*>(pBase)->Base::protected_member ...
class Base
{
protected:
int b;
public:
...
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b += static_cast<const Derived*>(&that)->Base::b;
d=0;
}
void DoSomething(const Base* that)
{
b += static_cast<const Derived*>(that)->Base::b;
d=0;
}
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething()
{
b+=this->b;
d=0;
}
};
//this will work
Following the hack for stl I wrote a small code which seems to solve the problem of accessing the protected members in derived class
#include <iostream>
class B
{
protected:
int a;
public:
void dosmth()
{
a = 4;
}
void print() {std::cout<<"a="<<a<<std::endl;}
};
class D: private B
{
public:
void dosmth(B &b)
{
b.*&D::a = 5;
}
};
int main(int argc, const char * argv[]) {
B b;
D d;
b.dosmth();
b.print();
d.dosmth(b);
b.print();
return 0;
}
Prints
a=4
a=5
Use this pointer to access protected members
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
this->b+=that.b;
d=0;
}
};
Let's see the following C++ codes.
Each inherited class has its member variables and initialization function.
These member variables are some different(almost same type) between inherited classes.
Is there any good way to move (or merge) this initialization into base class?
class Base {
public:
virtual init() = 0;
}
class A: public Base {
public:
int a1;
void init() { a1 = 0;}
}
class B: public Base {
public:
int b1;
void init() { b1 = 1;}
}
No. Base has no knowledge of A::a1 or B::b1. More importantly it should not have any knowledge of it's subclass members as this leads to a fundamental breakdown of the encapsulation you're trying to achieve in the first place.
The best you can do is have your Base class define a virtual method for initialisation and control when that method is called. It is up to each subclass to override the method and ensure that when initialisation is needed it is performed according to each subclass's respective requirements.
One thing to note is that if your initialisation is intended to be once-off for the lifetime of each object, the the correct place to do this is using constructors as per koizyd's answer.
On a related note, I'd like to point out that what you're asking is a variation on one of the most common OO design flaws I've seen in my career.
Using inheritance for code reuse not encapsulation.
Basically you're trying to push functionality into the base class (for reuse), and all this really achieves is making the Base class large, top-heavy and unmaintainable.
In C++ we can't (almost always) create function init, we use constructors
e.g
class Base {
};
class A : public Base {
public:
int a1;
A():Base(), a1(0) {}
};
class B : public Base {
public:
int b1;
B():Base(), b1(1){}
};
Construct "child" is A():Base(),a1(0), it's initializer list (:Base(),a1(0)), which create Base object, and int b1.
You should remember about ; after class.
I'd probably structure code like this:
class Base {
public:
void init() { sub_init(); }
protected:
virtual void sub_init() = 0;
}
class A: public Base {
public:
int a1;
protected:
void sub_init() { a1 = 0;}
}
class B: public Base {
public:
int b1;
protected:
void sub_init() { b1 = 1;}
}
The alternative of doing something like (syntax probably not correct...):
class Base {
public:
virtual void init() = 0;
protected:
void generic_init<T>(T &foo, T const &bar) { foo = bar; }
}
class A: public Base {
public:
int a1;
void init() { generic_init<int>(a1, 0); }
}
class B: public Base {
public:
int b1;
void init() { generic_init<int>(b1, 1); }
}
Looks awful to me!
Maybe you could use the template class skills to solve the problem. Like:
template <typename T> class Base {
public :
virtual void init( T t ) = 0;
};
class A: public Base<T> {
public:
T a1;
void init( T t ) { a1 = t;}
}
class B: public Base<T> {
public:
T b1;
void init( T t ) { b1 = t;}
}
You could have a try.
I ran into an error yesterday and, while it's easy to get around, I wanted to make sure that I'm understanding C++ right.
I have a base class with a protected member:
class Base
{
protected:
int b;
public:
void DoSomething(const Base& that)
{
b+=that.b;
}
};
This compiles and works just fine. Now I extend Base but still want to use b:
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b+=that.b;
d=0;
}
};
Note that in this case DoSomething is still taking a reference to a Base, not Derived. I would expect that I can still have access to that.b inside of Derived, but I get a cannot access protected member error (MSVC 8.0 - haven't tried gcc yet).
Obviously, adding a public getter on b solved the problem, but I was wondering why I couldn't have access directly to b. I though that when you use public inheritance the protected variables are still visible to the derived class.
A class can only access protected members of instances of this class or a derived class. It cannot access protected members of instances of a parent class or cousin class.
In your case, the Derived class can only access the b protected member of Derived instances, not that of Base instances.
Changing the constructor to take a Derived instance will solve the problem.
protected members can be accessed:
through this pointer
or to the same type protected members even if declared in base
or from friend classes, functions
To solve your case you can use one of last two options.
Accept Derived in Derived::DoSomething or declare Derived friend to Base:
class Derived;
class Base
{
friend class Derived;
protected:
int b;
public:
void DoSomething(const Base& that)
{
b+=that.b;
}
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b+=that.b;
d=0;
}
};
You may also consider public getters in some cases.
As mentioned, it's just the way the language works.
Another solution is to exploit the inheritance and pass to the parent method:
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
Base::DoSomething(that);
d=0;
}
};
You have access to the protected members of Derived, but not those of Base (even if the only reason it's a protected member of Derived is because it's inherited from Base)
You can try with static_cast< const Derived*>(pBase)->Base::protected_member ...
class Base
{
protected:
int b;
public:
...
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
b += static_cast<const Derived*>(&that)->Base::b;
d=0;
}
void DoSomething(const Base* that)
{
b += static_cast<const Derived*>(that)->Base::b;
d=0;
}
};
class Derived : public Base
{
protected:
int d;
public:
void DoSomething()
{
b+=this->b;
d=0;
}
};
//this will work
Following the hack for stl I wrote a small code which seems to solve the problem of accessing the protected members in derived class
#include <iostream>
class B
{
protected:
int a;
public:
void dosmth()
{
a = 4;
}
void print() {std::cout<<"a="<<a<<std::endl;}
};
class D: private B
{
public:
void dosmth(B &b)
{
b.*&D::a = 5;
}
};
int main(int argc, const char * argv[]) {
B b;
D d;
b.dosmth();
b.print();
d.dosmth(b);
b.print();
return 0;
}
Prints
a=4
a=5
Use this pointer to access protected members
class Derived : public Base
{
protected:
int d;
public:
void DoSomething(const Base& that)
{
this->b+=that.b;
d=0;
}
};
I have a base class with a member variable (preferably private) and I need to enforce derived classes to initialize it with a value based on their implementation; much like a pure virtual function.
To clarify, I want to declare a member in Base, have derived classes initialize it, and if they don't they get a compiler error. In the following code, I declared default constructor of Base to be protected. Then declared default constructor of Derived to be private.
class Base {
private:
int _size;
protected:
Base(){}
/* pure virtual methods */
public:
Base(int size) : _size(size){} // must enforce derived to call this.
virtual ~Base(){}
/* more pure virtual methods */
};
class Derived : public Base {
private:
Derived() {}
public:
Derived(int size) : Base(size) {
//Base::Base(size);
}
};
int main()
{
Derived* d1 = new Derived(); // throws an error as needed:
// "Cannot access private member declared in class 'Derived'"
Derived* d2 = new Derived; // throws an error as needed:
// "Cannot access private member declared in class 'Derived'"
Derived* d3 = new Derived(5); // works as needed
return 0;
}
The problem with the above code is that if another definition of Derived doesn't hide the default constructor. I'm still stuck with an uninitialized Base::_size.
I don't know if there is another way to go about this other than inheritance, because I still need derived classes to implement their own behavior for several methods declared in Base.
Any pointers are appreciated.
After the confusion about calling a base class ctor and default ctors, maybe the solution is just to not have a default ctor in Base?
class Base {
private:
int _size;
public:
// no default ctor
Base(int size) : _size(size) {} // must enforce derived to call this.
virtual ~Base(){}
/* more pure virtual methods */
};
class Derived : public Base {
public:
// no default ctor
Derived(int size) : Base(size){
}
// examplary default ctor:
//Derived() : Base(42) {}
};
int main()
{
Derived d1; // error: no default ctor
Derived* d2 = new Derived; // same, but why use the free store?
Derived d3(5); // works as needed
Derived* d4 = new Derived(5); // same, but why use the free store?
return 0;
}
To be explicit about not having a default ctor, one could use
class Base {
/* ... */
Base() = delete;
/* ... */
};
Use a constructor
class Base1 {
protected:
Base1(int forward) {
thingYouWantToHide = forward;
}
private:
int thingYouWantToHide;
};
class Derived1: public Base1 {
public:
Derived1(): Base1(5) {}
};
class Base2 {
private:
int value;
protected:
Base2() {
value = calledToGet();
}
virtual int calledToGet() = 0;
virtual ~Base2() {} //shut compiler warnings up
};
class Derived2: public Base2 {
virtual int calledToGet() {
return 5;
}
};
int main(int,char**) {
Derived1 a;
Derived2 b;
return 0;
}
You may think Derived2 will work, but remember Derived2 is not constructed until Base2 is, so that virtual is an undefined reference when Base2 is being constructed.
You should use the first case, type-traits if it is a constant (static const) or fundamental to the type.
I have a hierarchy that looks something like this:
class Base
{
public:
void Execute();
virtual void DoSomething() = 0;
private:
virtual void exec_();
};
class Derived : public Base
{
public:
//DoSomething is implementation specific for classes Derived from Base
void DoSomething();
private:
void exec_();
};
void Base::Execute()
{
// do some work
exec_(); //work specific for derived impl
// do some other work
}
void Derived::DoSomething()
{
//impl dependent so it can only be virtual in Base
}
int main()
{
Derived d;
Base& b = d;
b.Execute(); //linker error cause Derived has no Execute() function??
}
So the question is how do I call Execute() using this pattern when I create a derived using my Base class. In my case I do not want to create Derived directly, as I have multiple classes derived from Base and depending on some condition I have to pick a different derived class.
can anyone help?
This
class Base
{
public:
void Execute();
private:
virtual void exec_() {}
};
class Derived : public Base
{
private:
void exec_() {}
};
void Base::Execute()
{
// do some work
exec_(); //work specific for derived impl
// do some other work
}
int main()
{
Derived d;
Base& b = d;
b.Execute();
}
compiles, links, and runs for me.
You should probably also make exec_() pure virtual in your base class. You then also need to implement it in your derived classes.
You need to write a function definition for exec_() function.