These three keywords are also used in a completely different context to specify the visibility inheritance model.
This table gathers all of the possible combinations of the component declaration and inheritance model presenting the resulting access to the components when the subclass is completely defined.
The table above is interpreted in the following way (take a look at the first row):
if a component is declared as public and its class is inherited as public the resulting access is public.
An example:
class Super {
public: int p;
private: int q;
protected: int r;
};
class Sub : private Super {};
class Subsub : public Sub {};
The resulting access for variables p
, q
, r
in class Subsub is none.
Another example:
class Super {
private: int x;
protected: int y;
public: int z;
};
class Sub : protected Super {};
The resulting access for variables y
, z
in class Sub is protected and for variable x
is none.
A more detailed example:
class Super {
private:
int storage;
public:
void put(int val) { storage = val; }
int get(void) { return storage; }
};
int main(void) {
Super object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
Now lets define a subclass:
class Sub : Super { };
int main(void) {
Sub object;
object.put(100);
object.put(object.get());
cout << object.get() << endl;
return 0;
}
The defined class named Sub which is a subclass of class named Super
or that Sub
class is derived from the Super
class.
The Sub
class introduces neither new variables nor new functions. Does it mean that any object of the Sub
class inherits all the traits after the Super
class being in fact a copy of a Super
class’ objects?
No. It doesn’t.
If we compile the following code, we will get nothing but compilation errors saying that put
and get
methods are inaccessible. Why?
When we omit the visibility specifier, the compiler assumes that we are going to apply the so-called private inheritance. It means that all public superclass components turn into private access, private superclass components won't be accessible at all. It consequently means that you are not allowed to use the latter inside the subclass.
We have to inform the compiler that we want to preserve the previously used access policy.
class Sub : public Super { };
Don’t be misled: it doesn’t mean that private components of the Super
class (like the storage variable) will turn into public ones in a
somewhat magical way. Private components will remain private, public
will remain public.
Objects of the Sub
class may do "almost" the same things as their older siblings created from the Super
class. "Almost" because the fact of being a subclass also means that the class lost access to the private components of the superclass. We cannot write a member function of the Sub
class which would be able to directly manipulate the storage variable.
This is a very serious restriction. Is there any workaround?
Yes.
The third access level is called protected. The keyword protected means that the component marked with it behaves like a public one when used by any of the subclasses and looks like a private one to the rest of the world. -- This is true only for the publicly inherited classes (like the Super class in our example) --
class Super {
protected:
int storage;
public:
void put(int val) { storage = val; }
int get(void) { return storage; }
};
class Sub : public Super {
public:
void print(void) {cout << "storage = " << storage;}
};
int main(void) {
Sub object;
object.put(100);
object.put(object.get() + 1);
object.print();
return 0;
}
As you see in the example code we a new functionality to the Sub
class and it does one important thing: it accesses the storage variable from the Super class.
It wouldn’t be possible if the variable was declared as private.
In the main function scope the variable remains hidden anyway so if you write anything like:
object.storage = 0;
The compiler will inform you that it is an error: 'int Super::storage' is protected
.
Finally, the last program will produce the following output:
storage = 101
No comments:
Post a Comment