I am confused: I thought protected data was read/writable by the children of a given class in C++.
The below snippet fails to compile in MS Compiler
class A
{
protected:
int data;
};
class B : public A
{
public:
B(A &a)
{
data = a.data;
}
};
int main()
{
A a;
B b = a;
return 0;
}
Error Message:
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
demoFail.cpp
demoFail.cpp(12) : error C2248: 'A::data' : cannot access protected member declared in class 'A'
demoFail.cpp(4) : see declaration of 'A::data'
demoFail.cpp(2) : see declaration of 'A'
What am I doing wrong?
According to TC++PL, pg 404:
A derived class can access a base class’ protected members only for objects of its own type.... This prevents subtle errors that would otherwise occur when one derived class corrupts data belonging to other derived classes.
Of course, here's an easy way to fix this for your case:
class A
{
protected:
int data;
};
class B : public A
{
public:
B(const A &a)
: A(a)
{
}
};
int main()
{
A a;
B b = a;
return 0;
}
The C++ Standard says about protected non-static members at 11.5/1
When a friend or a member function of a derived class references a protected nonstatic member function or protected nonstatic data member of a base class, an access check applies in addition to those described earlier in clause 11. Except when forming a pointer to member (5.3.1), the access must be through a pointer to, reference to, or object of the derived class itself (or any class derived from that class) (5.2.5). If the access is to form a pointer to member, the nested-name-specifier shall name the derived class (or any class derived from that class).
In addition to fixing things mentioned earlier by others (constructor of B is private), i think rlbond's way will do it fine. However, a direct consequence of the above paragraph of the Standard is that the following is possible using a member pointer, which arguably is a hole in the type system, of course
class B : public A {
public:
B(A &a){
int A::*dataptr = &B::data;
data = a.*dataptr;
}
};
Of course, this code is not recommended to do, but shows that you can access it, if you really need to (I've seen this way being used for printing out a std::stack, std::queue, std::priority_queue by accessing its protected container member c)
You just shouldn't copy an A object in a B constructor. The intention is to leave the initialization of A's members to it's own constructor:
struct A {
A( const A& a ): data( a.data ) {}
protected: int data;
};
struct B : public A {
B( const A& a ): A( a ) {}
};
The constructor of B is private. If you do not specify anything, in a class, the default modifier is private (for structs it is public). So in this example the problem is that you cannot construct B. When you add public to constructor B anoter problem arises:
B has the right to modify the part of A it derives from but not another A like in this case.
You could do following:
class A
{
public:
A()
: data(0)
{
}
A(A &a)
{
data = a.data;
}
protected:
int data;
};
class B : public A
{
public:
B(A &a)
: A(a)
{
}
};
int main()
{
A a;
B b = a;
return 0;
}
Related
I'm learning c++ inheritance and facing problems with the following exercise to create a base class A and a derived class B with certain requirements. I have my answer written down below, but there seems to be some problems with it. I also have a few question at the end of this post.
class A {
private:
int x;
protected:
A (): x(0) { }
A (int n): x(n) { }
int get() const {return x;}
public:
virtual void foo() = 0;
};
class B : public A {
public:
B (): { A(); }
B (int n): { A(n); }
virtual void foo() { std::cout << get();}
};
My questions are:
I'm pretty sure my code is not correctly written, but can anyone tell me what's incorrect?
Since x is private in A, B wouldn't be able to inherit that data member. So how is B able to invoke the constructor?
I'm pretty sure that A is an abstract class, but is B an abstract class too?
It's almost okay, there's two thing that is wrong:
First you have an empty constructor initializer list in the B constructors. That will lead to build errors.
Then in the B constructor the statement A() creates a temporary A object, which is promptly discarded and destructed. You need to "call" the parent class constructor from the B constructor initializer list:
B() : A() { /* Empty */ }
You meed to do the same for the parameterized B constructor as well.
You can't access private members in the base-class, but protected is okay. That's now protected works with public inheritance: The child class can access the base class protected members.
Since you override foo with an implementation B is not abstract, there's no abstract members of B.
Why the derived class Derived_from_Private is illegal?
i noticed the member function has an reference to Base, but why it cannot have an reference to Base class?
class Base {
public:
void pub_mem(); // public member
protected:
int prot_mem; // protected member
private:
char priv_mem; // private member
};
struct Pub_Derv : public Base {
// legal
void memfcn(Base &b) { b = *this; }
};
struct Priv_Derv : private Base {
// legal
void memfcn(Base &b) { b = *this; }
};
struct Prot_Derv : protected Base {
// legal
void memfcn(Base &b) { b = *this; }
};
struct Derived_from_Public : public Pub_Derv {
// legal
void memfcn(Base &b) { b = *this; }
};
struct Derived_from_Private : public Priv_Derv {
// illegal
void memfcn(Base &b) { b = *this; }
};
struct Derived_from_Protected : public Prot_Derv {
// legal
void memfcn(Base &b) { b = *this; }
};
The expression
b = *this;
needs to invoke an implicit conversion from *this to an lvalue of type Base in order to call the implicitly declared Base::operator=(const Base&). This conversion goes through the path Derived_from_Private -> Priv_Derv -> Base. Since Priv_Derv has Base as a private base, Derived_from_Private does not have access to the second link.
Priv_Derv inherits privately Base. This means that only the class itself knows that it's also a Base and only the member functions of Priv_Derv can use members of Base.
You can later let Derived_from_Private inherit publicly from Priv_Derv. It's legal. But unfortunately, due to the former private inheritance, it's as if Derived_from_Private doesn't have Base as base class.
Therefore your member function will fail to compile:
void memfcn(Base &b) { b = *this; }
*this is a Derived_from_Private, but it's illegal to convert it to a Base class, because there is no known relation with that class due to the private inheritance.
Inheritance can provide both subtyping and structural extension.
When you inherits privately from a base class you have no subtyping, only structural extension. Then (in your problematic case) when you write b = *this alas *this is not of the type Base because you have used private inheritance of it.
Private inheritance is usually used (that doesn't mean it's a good practice) to easily construct very simple composition (has a base, but not is a base).
A name of a class is inserted into the scope of itself as a public member. This is so-called injected-class-name. Name lookup for Base in the derived class Derived_from_Private will find its injected-class-name instead of the normal one. Because the injected-class-name of Base is treated as a public member of Base, thus is treated as a private number of Priv_Derv, it is inaccessible in Derived_from_Private.
Quoted from [class.access.spec] paragraph 5:
[ Note: In a derived class, the lookup of a base class name will find the injected-class-name instead of the name of the base class in the scope in which it was declared. The injected-class-name might be less accessible than the name of the base class in the scope in which it was declared. — end note ] [ Example:
class A { };
class B : private A { };
class C : public B {
A* p; // error: injected-class-name A is inaccessible
::A* q; // OK
};
— end example ]
I am not an advanced programmer. Suppose there is a classic diamond inheritance:
class Base
class A: virtual public Base
class B: virtual public Base
class Last: public A, public B
Suppose Base has a variable, m_x, that is common to both A and B, such that only one of A, or B, can be called at a time, not both (which is what is needed). To get around this, this is used:
class Last: public A, public B
{
private:
std::unique_ptr<Base> m_p;
public:
Last(int i)
{
if (i)
m_p = std::unique_ptr<Base>(new A());
else
m_p = std::unique_ptr<Base>(new B());
}
};
This is fine, but now m_p->m_x cannot be accessed anymore because it says it's protected, but both A and B call m_x in their constructors directly, with no problems.
Is this a known limitation or is this the wrong way to do it? If it's wrong, what solutions are there?
Here is some code based on the diagram found here (a bit lower on the page):
#include <iostream>
#include <memory>
class Power
{
protected:
double m_x;
public:
Power() {}
Power(double x): m_x {x} {}
virtual ~Power() = default;
};
class Scanner: virtual public Power
{
public:
Scanner() {}
Scanner(double x): Power(x) {} // scan document
};
class Printer: virtual public Power
{
public:
Printer() {}
Printer(double x): Power(x) {} // print document
};
class Copier: public Scanner, public Printer
{
private:
std::unique_ptr<Power> m_p;
public:
Copier() {}
Copier(double x, int i)
{
if (i)
m_p = std::unique_ptr<Power>(new Scanner(x));
else
m_p = std::unique_ptr<Power>(new Printer(x));
}
void print() { std::cout << this->Power::m_x << '\n'; }
};
int main(int argc, char *argv[])
{
Copier *copier {new Copier(1.618, 0)};
copier->print();
copier = new Copier(3.14, 1);
copier->print();
return 0;
}
Using both this->m_p and this->Power::m_x (according to answers and comments) compiles, but the output is 0.
To be sure I spell it out all: not only I am quite a beginner, but, given the example above, it oesn't really have to stay that way if there is another alternative to call Scanner or Printer only one at a time from inside Copier. I am not asking for opinions, I understand it's forbidden, but I won't reject them coming from more experienced users. After all, I am learning.
Both virtual inheritance and std::unique_ptr are red herrings. The problem comes down to this:
class Base
{
protected:
int m_x;
};
class Last : public Base
{
public:
Last()
{
Base base;
base.m_x = 0; // error
m_x = 1; // no error
}
};
The error is something like error C2248: 'Base::m_x': cannot access protected member declared in class 'Base' or error: 'int Base::m_x' is protected within this context.
The explanation is that protected is a somewhat special case. It does not only work on class level but also on the object level. And you have two relevant objects here:
The Last object which is being created by the constructor, i.e. the one pointed to by this. It's also a Base object because of the is-a inheritance relationship.
The local object named base within the constructor.
Now, the problem is that in the line base.m_x = 0;, you are in the context of the first object and not the second one. In other words, you are trying to access the m_x of base from outside base. C++ simply does not allow this.
A very technical explanation can be found in the C++ standard at §11.4 [class.protected], a more easily understandable one in an excellent answer here on Stack Overflow.
protected doesn't mean quite what you think it does.
Although Last is derived from Base, member functions of Last don't have access to the protected members of any Base object - just those Base objects that are sub-objects of some Last object.
So you can write: this->Base::x because *this is a Last object, but not m_p->x, because *m_p is of static type Base.
As others have noted, I think this is actually an XY problem. Having an object which derives from two classes, and then also has a pointer to another object of one of those classes is very strange indeed. I think you need to clarify what you are trying to do.
Program:
class A
{
int a;
public:
void geta()
{
a=10;
}
void puta()
{
cout<<"a : "<<a;
}
};
class B : public A
{
int b;
public:
void getb()
{
geta(); b=20;
}
void putb()
{
puta(); cout<<"b : "<<b;
}
};
int main()
{
B ABC;
ABC.getb();
ABC.putb();
return 0;
}
The Problem:
The above program allocates memory for derived class object & calls its relevant methods.
The base class is inherited as public, and as the variable 'a' is a private member, it will not get inherited.
So, the program should not allocate memory for this variable.
But, when the above is executed, 'a' variable will be allocated even though it is not inherited.
Could anyone help me understand this?
Thank You.
as the variable 'a' is a private member, it will not get inherited. So, the program should not allocate memory for this variable.
Your assumption is mistaken. Public inheritance models an "is-a" relationship. That is, class Derived is-a Base. Anything you can do with a Base, you should be able to do with a Derived. In order for this to be true, it necessarily must contain everything that Base contains.
In your example, it's perfectly legal to say:
B b;
b.put_a();
that is, to use A methods on B object. This would not work if the a member was absent.
The base class is inherited as public, and as the variable 'a' is a private member, it will not get inherited.
When a base class member is declared as private it doesn't mean it does not get inherited. It just means that the member variable will be inherited (will be part of the derived class) but won't be accessible.
For example, in:
class A {
private:
int a;
int b;
// ...
};
class B : public A {};
auto main() -> int {
B b;
}
When we allocate B b; we are allocating both a and b member objects of the class A.
The variable a is inherited, though you have no access to it. For example, the following code would work:
class A {
private:
int x;
public:
int getXfromA() { return x; }
};
class B : public A {
public:
int getXfromB() { return getXfromA(); }
};
However, x cannot be directly accessed from B class here.
You're confusing storage with access control.
If object B inherits from object A, it has all of object A's methods and members, even if it cannot access them directly.
The purpose of private and protected is access control. If you mark members and methods as private, then nothing outside can access those methods and members. But, those things are part of the object nonetheless.
This allows you to implement class invariants without exposing the details, including classes that inherit from the base.
Here's an example that encapsulates capturing the creation time of an object in the base class:
#include <time.h>
#include <iostream>
class Base
{
private:
time_t create_time;
public:
Base()
{
create_time = time(0);
}
time_t get_create_time() { return create_time; }
};
class Derived : public Base
{
public:
Derived() { }
};
int main()
{
Derived D;
std::cout << D.get_create_time() << std::endl;
}
Derived doesn't know or need to know how the creation time was captured. It's a class invariant it inherited by deriving from Base.
This is a pretty simple example, but you could imagine more complex examples.
It seems that a protected member from a template policy class is inaccessible, even with a class hierarchy which seems correct.
For instance, with the following code snippet :
#include <iostream>
using namespace std;
template <class T>
class A {
protected:
T value;
T getValue() { return value; }
public:
A(T value) { this->value = value; }
};
template <class T, template <class U> class A>
class B : protected A<T> {
public:
B() : A<T>(0) { /* Fake value */ }
void print(A<T>& input) {
cout << input.getValue() << endl;
}
};
int main(int argc, char *argv[]) {
B<int, A> b;
A<int> a(42);
b.print(a);
}
The compiler (clang on OS X, but gcc returns the same type of error) returns the following error :
Untitled.cpp:18:21: error: 'getValue' is a protected member of 'A<int>'
cout << input.getValue() << endl;
^
Untitled.cpp:25:5: note: in instantiation of member function 'B<int, A>::print' requested here
b.print(a);
^
Untitled.cpp:8:7: note: can only access this member on an object of type 'B<int, A>'
T getValue() { return value; }
^
1 error generated.
The strange thing is that the last note from the compiler is totally correct but already applied since the b object is of type 'B<int, A>'. Is that a compiler bug or is there a problem in the code ?
Thanks
You have misunderstood the meaning of protected access.
Protected members are callable by derived classes. But only on the base object contained inside the class itself.
For example, if i simplify the problem, using :
class A {
protected:
void getValue(){}
};
class B : protected A
{
public:
void print(A& input)
{
input.getValue(); //Invallid
}
};
getValue cannot be called on a "A" object other than the "A" object inside the class itself.
This for example is valid.
void print()
{
getValue(); //Valid, calling the base class getValue()
}
As pointed out by Dan Nissenbaum and shakurov. This is however also valid:
void print(B& input)
{
input.getValue();
}
This is because we explicitly say that input is a object of B. And the compiler know that all that objects of B has protected access to getValue. In the case when we pass a A&, the object might as-well be a type of C, wich could be derrived from A with private access.
Let's forget for a minute about the template and look at this:
class A {
protected:
int value;
int getValue() { return value; }
public:
A(int value) { this->value = value; }
};
class B : protected A {
public:
B() : A(0) { /* Fake value */ }
void print(A& input) {
cout << input.getValue() << endl;
}
};
The print() method's implementation is wrong because you can't access non-public member of A inside B. And here's why: from within B, you can only access non-public members of B. Those members may be either inherited or not — it doesn't matter.
On the other hand, A& input may not be a reference to an instance of B. It may be a reference to another subclass (which may well have getValue() inaccessible).
Member functions of a derived class have access to protected base class members within any object of its type that is passed as an argument so long as the explicitly declared class of the object passed as an argument is that of the the derived class (or a further derived class).
Objects explicitly passed as the base class type cannot have their protected members accessed within the derived class's member functions.
In other words, if we have:
class A
{
protected:
int x;
}
class B : public A
{
void foo(B b)
{
b.x; // allowed because 'b' is explicitly declared as an object of class B
}
void goo(A a)
{
a.x; // error because 'a' is explicitly declared as having *base* class type
}
};
...then the line a.x is not allowed because the explicit type of the argument is A, but the rule for protected access only applies to objects explicitly defined as the same class as the class attempting to access the member. (...Or a class derived from it; i.e., if class Cderives from B, then passing an object explicitly declared as an object of class C will also have x accessible within B member functions.)
The reason for this is given by shakurov when he writes (paraphrasing)
A& input might not be a reference to an instance of B. It may be a
reference to another subclass (which may well have getValue()
inaccessible)
An excellent explication of this answer is also given here: accessing a protected member of a base class in another subclass.
As a matter of interest, I believe that this comes from the C++ standard here:
11.4 Protected member access [class.protected] 1 An additional access check beyond those described earlier in Clause 11 is applied when a
non-static data member or non-static member function is a protected
member of its naming class (11.2)115 As described earlier, access to a
protected member is granted because the reference occurs in a friend
or member of some class C. If the access is to form a pointer to
member (5.3.1), the nested-name-specifier shall denote C or a class
derived from C. All other accesses involve a (possibly implicit)
object expression (5.2.5). In this case, the class of the object
expression shall be C or a class derived from C.
Don't get distracted by the template. It has nothing to do with the error. The line in main that the compiler is complaining about creates an object of type B<int, a> and tries to access a protected member. That's not legal, regardless of the type. You can only use protected members from inside a member function or friend function. For example:
struct S {
protected:
void f();
};
int main() {
S s;
s.f(); // error: attempts to call a protected member function
}