I'm learning C++. The documentation learn.microsoft.com/en-us/cpp/cpp/member-access-control-cpp says:
When you specify a base class as private, it affects only nonstatic members. Public static members are still accessible in the derived classes.
However, the following code slightly adjusted from the example following the previous quote cause error C2247:
'Base::y' not accessible because 'Derived1' uses 'private' to inherit from 'Base'.
I will appreciate any help with this situation.
class Base
{
public:
int x;
static int y;
};
class Derived1 : private Base
{
};
class Derived2 : public Derived1
{
public:
int ShowCount();
};
int Derived2::ShowCount()
{
int cCount = Base::y;
return cCount;
}
That documentation is a little misleading.
The correct compiler behaviour is for Base::y and Base::x to both be inaccessible in Derived, if you use that notation to attempt to reach the static member.
But you can reach it via the global namespace (thereby circumventing Derived1) by using another scope resolution operator:
int Derived2::ShowCount()
{
int cCount = ::Base::y;
return cCount;
}
Finally, don't forget to define y somewhere if you want the link stage to be successful.
Change this:
Base::y;
to this;
::Base::y;
Related
An example to illustrate my problem:
class Base
{
protected:
int x{ 0 };
};
class DerivedClass1 : public Base
{
};
class DerivedClass2 : public DerivedClass1
{
public:
int getX() const
{
return x;
}
};
int main()
{
DerivedClass2 d2{};
int x{ d2.getX() };
return 0;
}
I can access the protected member of Base in theDerivedClass2 class, although the protected members of Base should only be changed in DerivedClass1. By inheriting the variable in Base to DerivedClass1 a class shall be formed, which the DerivedClass2 must not manipulate. In C# this is possible with the private protected keyword, but how can you handle it in C++?
What are the consequences of protected?
It is the very idea of protected to allow all the derived classes to access such members.
While this is a very flexible language feature, it creates a serious weakness in the encapsulation, which encourages breaking the Liskov Substitution Principle (more precisely the history constraint, since a derived class could alter the state of a base object without going through a base class primitive).
How to avoid its drawbacks ?
If you want a stronger encapsulation and restrictive access, you'd need to go to private. This ensure that the inner state of a base class can only be accessed using the public interface. (Note that while it ensures the history constraint, it doesn't on its own guarantee LSP). And the consequence is that no derived class gets access. Not at first derivation, and not later.
Do you need private protected ?
What you want, is a kind of in-between: a weak encapsulation, but not too weak. This doesn't exist in C++. And I'm not sure it would strengthen your design.
But if you need this limitation on exceptional basis, there could be a work-around, playing with the name lookup:
class DerivedClass1 : public Base
{
private:
using Base::x;
// In DerivedClass1 you can still use x.
};
// But it will fail to compile in Derived2
Online demo
But personally I would not advise to go this way. It's error prone (you could forget the using in one sibling derived). The compiler error messages might be misleading. And anyway, private yields more robust design.
You could declare the data member as private and use friend-declarations to explicitly specify which classes may access it though:
class Base
{
friend class DerivedClass1;
private:
int x = 0;
};
class DerivedClass1 : public Base
{
void test() {
cout << x; // OK: DerivedClass1 is a friend of Base
}
};
class DerivedClass2 : public DerivedClass1
{
public:
int getX() const
{
return x; // ERROR: x is a private member
}
};
Inherit a 'private' Base:
class DerivedClass1 : private Base
{
};
Edit: Expose public or protected members in Base through public or protected members in DerivedClass1. DerivedClass1 then has complete control over what Base members can and cannot be accessed by classes inheriting from DerivedClass1.
Whether that's a good solution depends on the complexity of Base.
Due to the layout of a third-party library, I have something like the following code:
struct Base
{
static void SomeStaticMethod(){}
};
struct Derived1: private Base {};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Base::SomeStaticMethod();
}
};
int main() {
Derived2 d2;
d2.SomeInstanceMethod();
return 0;
}
I'm getting compiler error C2247 with MSVC:
Base::SomeStaticMethod not accessible because Derived1 uses private to inherit from Base.
I know I can't access Base members from Derived2 via inheritance because of the private specifier, but I should still be able to call a static method of Base - regardless of any inheritance relationship between Base and Derived2.
How do I resolve the ambiguity and tell the compiler I'm just making a call to a static method?
Do this:
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
::Base::SomeStaticMethod();
// ^^
// Notice leading :: for accessing root namespace.
}
};
I think michalsrb's answer is better, but for completeness:
namespace
{
void SomeStaticMethodProxy()
{
return Base::SomeStaticMethod();
}
}
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
SomeStaticMethodProxy();
}
};
will also work.
Other answers provide way to solve the problem, I'll try to explain what's happening. It's because of injected-class-name.
9.2 (N4594)
[...]The class-name is also inserted into the scope of the class itself; this is known as the injected-class-name.
For purposes of access checking, the injected-class-name is treated as if it were a public member name.[...]
Note that even if you type Base::SomeStaticMethod(), obviously SomeStaticMethod is looked up in Base scope (It's qualified name), but name Base itself also has to be looked up somehow, (In this example as an unqualified name (because it does not appear after scope resolution operator))
What happens is that when you search for (unqalified) name Base in Derived2, first Derived2 scope is searched, then Derived1 scope is searched and then Base scope is searched and finally injected-class-name is found. Then access control takes place (because access control takes place after name lookup) and it'll find that name you looked up is Base's member which isn't accessible from Derived2.
You can do this if you want to call it through the hierarchy:
struct Derived1: private Base {
protected:
using Base::SomeStaticMethod;
};
struct Derived2: public Derived1 {
void SomeInstanceMethod(){
Derived1::SomeStaticMethod();
}
};
Otherwise, do as #michalsrb mentioned if you want to call it directly on Base.
A couple of possibilities:
Don't use the inheritance structure to call the method. Use ::Base::SomeStaticMethod() to call it. Base is accessible in the global namespace.
Bring the private function into the namespace of Derived1 by writing using Base::SomeStaticMethod;
Can you please explain me why I receive error trying to access the members of the nested class from the derived class:
class Base
{
public:
static int A;
class inside_Base {public: static int B;};
};
int Base::A = 1;
int Base::inside_Base::B = 2;
class Derived : public Base {};
then in main I have:
Base * p;
p = new Derived();
when I try to print p->inside_Base::B I receive below error:
error: 'Base::inside_Base' is not a base of 'Derived'
Thanks.
As #V.Kravchenko said, you should not use static members through created objects. There is no variables polymorphism, only the functions one.
Usually you do not need to refer to inside_Base through Derived, because you lie that the Base::inside_Base is a nested class of Derived. But if you want it very much, you can typedef it:
class Derived : public Base
{
public:
typedef Base::inside_Base inside_Base;
};
In this case you can write Derived::inside_Base::B, for example (checked in MSVC 9.0). But, of course, it has no polymorphism as the class is defined statically in compile time.
What means p->A? Why not p->inside_Base::B?
p->A is equivalent to Base::A. It is C++ feature that allow you to use static variables as non-static. Don't know why it is needed.
var->Class::member says that you want a member symbol from class Class related to var instance. It is needed to resolve ambiguous symbols that may be used with var. For example:
class Base
{
public:
int x = {1};
};
class Derived
{
public:
int x = {2};
};
void main()
{
Derived var
std::cout << var.x << " " << var.Base::x;
}
Out will be 2 1. In second call we want to get exactly Base's member.
So, p->inside_Base::B says that you want a B from exactly class inside_Base related to p variable. But inside_Base is not a p's class and not a derived one. You can ask: why compiler doesn't scan nested classes? I think that because nobody needs it. It will complicate compilation and will not benefit as it doesn't resolve any ambiguousness.
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.
So private members in the base class are also in the inherited class but not accessible in it, right?
Are they actually in the memory allocated to the the inherited object?
Are they actually in the memory allocated to the the inherited object?
Yes, they need to exist. The private members are part of the implementation detail of the base class. Without them, in general, the base class wouldn't be able to function (which is why they exist in the first place).
Making them private just allows the base class to create its implementation however it chooses, without exposing that to anybody, including the subclass.
Yes. Just for example, you can use a public function from the base class that manipulates private data, even in an instance of the derived class:
class Base {
int x;
public:
Base() : x(0) {}
void inc() { ++x; }
void show() { std::cout << x << "\n"; }
};
class Derived : public Base {
};
int main() {
Derived d;
d.show();
d.inc();
d.show();
}
With a properly functioning compiler, this must display:
0
1
...showing that the data in the Base object is present in the Derived object, even though it's not (directly) accessible.
Of course with almost anything in C++, there's the "as-if" rule -- if the compiler can determine that it can somehow produce the correct observable behavior for the program, even without including the private part(s) of the base class, then it's free to do so. The most obvious example of this would be if you included something (member function or data) in the base class that was simply never used in practice.
Yes they are,
When object of the derived class is being constructed all of its base classes are first being constructed as well.
Consider this example:
class Base
{
int x;
public:
Base(int px)
: x(px)
{
}
};
class Derived : public Base
{
int y;
public:
Derived(int px, int py)
: y(py), Base(px)
{
}
};
This example compiles and works and Base is initialized (constructor is called) before you reach the body of the Derived constructor.