The following code doesn't compile:
class C
{
private:
int m_x;
protected:
C(int t_x) : m_x(t_x) { }
};
class D : public C
{
public:
using C::C;
};
int main(int argc, char **argv)
{
D o(0);
}
The compiler's objection is that the constructor for C is declared protected, meaning that I can't access it from main. In other words, it seems like the using declaration drags the original visibility of the identifier with it, despite the fact that it lives in the public block.
Two questions:
Why does this happen? (Both in terms of the rules for how this works, and the rationale for making those rules).
Is there any way I can get around this without explicitly writing a constructor for D?
This is a subtle one. In C++, employing the using keyword on a base class constructor is called inheriting constructors and works differently than what a using keyword typically does. Specifically, note that
If overload resolution selects an inherited constructor, it is accessible if it would be accessible when used to construct an object of the corresponding base class: the accessibility of the using-declaration that introduced it is ignored.
(Emphasis mine. Source)
In other words, the fact that you've included the using declaration in a public section doesn't actually make those constructors public.
I believe that, in this case, you may have to define your own constructors to match the base type constructors.
statement using C::C; is not about increasing visibility, but, about since c++11
feature called inheriting constructors, making constructor of base class C invoking when derived D is constructed. You cant change access modifier of constructor that way. But, you can change access modifier, of any function by explicitly redeclaring it in a derived class with the different access modifier.
Related
I am a beginner in C++, I had a question regarding nested class in C++, how do you access the protected or private member of an enclosed class?
class A{
class B{
protected:
B(){};
};
B var; <=== error as the constructor B is protected
};
One solution is making constructor of B public, but this exposes it'a scope and other function can instantiate it, which I don't want. What's a way to do deal with this ?
You can use friend class:
class A
{
class B
{
friend class A; //<-- makes A a friend of B
protected:
B(){};
};
B var; //<-- OK
};
I believe the question that was asked does not get at the real issue. It is almost an XY problem, but fortunately it has sufficient hints for the real issue to be deduced. Still, in the interest of propriety, I will address the question that was asked before addressing what I believe is the real issue.
how do you access the protected or private member of an enclosed class?
The same way you grant such access when the classes are not nested: the class with the protected or private member declares the other class (or function) as a friend. Just be aware that this is a bit of a sledgehammer approach, so it is advisable to consider alternatives first.
One solution is making constructor of B public, but this exposes it's scope and other function can instantiate it, which I don't want.
No, it doesn't expose anything outside A. You have declared B as a private type within A, which means only A can reference B. With your current setup, there is no functional difference between making A a friend of B and making all members of B public. In either case, A has full access to B and nothing outside A knows that B exists.
While I suspect that B is supposed to be public, the OP has had days to correct this detail. In addition, the OP posted a new question after this possible oversight was pointed out, so I must conclude that the OP does not regard it as an oversight.
Now we get to what I believe is the real issue: how to construct a public nested class from the outer class without allowing public construction.
What's a way to do deal with this ?
If there is a possibility that B might become a public type at some point (a reasonable thing to guard against), you should consider alternatives to friendship. One alternative is to put the constructor of B under lock-and-key. This could be extended to other private members of B, but that is perhaps not necessary.
One advantage of this approach is that access is granted to only the constructor, not to all private members. This helps preserve encapsulation. Furthermore, this approach allows construction to be handed off to helper functions, such as those from the standard library. For example, an emplace_back method for a standard container could construct a B object as long as the method was given a key. This might be more convenient than relying on friendship, depending on how B objects are to be used.
The key
The "key" is a private class of A. It is likely going to be an empty class, as it does not need functionality. All the key needs to do is exist and be inaccessible outside A.
class A{
private:
class KeyForB {};
// Rest of the definition of A
};
The lock
The "lock" is a constructor that accepts the "key" as a parameter. This parameter will not be used by the constructor; all it does is signify that the caller is allowed to call the constructor.
class B{
public:
/* explicit */ B(KeyForB /* unnamed */) : B() {}
protected:
B() {}
};
There are a few details worth looking at. First, you might have noticed that B just used a private member of A! How? There is a special rule that says that nested classes are considered part of the outer class, and as such they can access the private (and protected) members of the outer class – no friend declaration necessary.
Second, the lock delegates to the protected constructor. This may seem odd, but it does serve a purpose. Not only does it keep the default constructor available to B, but also it allows the compiler to optimize away the lock and key. Consider what would happen if the constructor was so large that the compiler opted to not inline it. If a function is not inlined, then parameters cannot be optimized away. In this case, that would mean that a KeyForB would need to be constructed and placed on the call stack. In contrast, the lock is so simple that it should be inlined under any level of optimization. It gets inlined to a call to B() and the unused KeyForB is eliminated from the executable.
Third, there is a comment acknowledging that some coding guidelines recommend marking as explicit most constructors that take a single parameter. This is sound advice. However, in this case, the only reason to create a KeyForB object is to construct a B object. So in this case, it might be acceptable and convenient to leave this conversion implicit.
Putting it together
The only remaining piece is to write a constructor for A, as the compiler-provided default constructor is deleted because it would be ill-formed.
class A{
private:
class KeyForB {};
//public: // <-- possible future change
class B{
public:
B(KeyForB) : B() {}
protected:
B() {}
};
public:
// Default constructor
A() : var(KeyForB{}) {}
private:
B var;
};
It might be worth noting that if the type of var were to change from B to std::shared_ptr<B>, this approach would not run into "make_shared for friend class throwing error", as giving a key to make_shared would enable construction.
This question already has an answer here:
C++11 inheriting constructors and access modifiers
(1 answer)
Closed 3 years ago.
class A {
protected:
A(int) {}
};
struct B : public A {
public:
using A::A;
};
void print(B b) {}
int main(int argc, char** argv) {
print(1);
return 0;
}
This code does not compile... Even with 'using A::A' in struct B public section, B still does not have a public constructor accepting an int (but it has a protected one).
It seems that :
I can inherit public constructor with 'using'
I can re-declare as public in derived class any method defined in base class (private or protected or else)
BUT I cannot do the same with a constructor : no way to alter its visibility with 'using'
Why ?
This is intentional. Note that A::A inherits every constructor, not just the one you are expecting. Applying the using's access modifier to every inherited constructor would likely be too far reaching. Instead, it simply makes them available for overload resolution.
From cppreference :
If the using-declaration refers to a constructor of a direct base of the class being defined (e.g. using Base::Base;), all constructors of that base (ignoring member access) are made visible to overload resolution when initializing the derived class.
If overload resolution selects an inherited constructor, it is accessible if it would be accessible when used to construct an object of the corresponding base class: the accessibility of the using-declaration that introduced it is ignored.
If you want to call A::A(int) when constructing a B, you can implement B::B(int) yourself such that it calls it.
If the current access specifier of the using declaration changed the access specifier of the "inherited" constructors, then there would be no way for separate "inherited" constructors to have different access specifier.
If the base class does have multiple constructors with differing access, then it would be typically desirable for the accessibility to remain in the derived class. The rules of using make this possible.
I have a class that looks something like this:
class A
{
public:
void foo(int arg) { foo(arg, false); }
private:
void foo(int arg, bool flag) {}
};
It is built this way because I want foo's flag argument to only be false when called from outside A. I want to inherit it privately, but allow calling foo:
class B : private A
{
public:
using A::foo;
};
However, this fails because the using declaraion attempts to bring all the overloads of foo into scope, including the private one, which the the compiler rightly rejects.
This isn't hard to fix, I can either:
Change the accessibility of A::foo(int, bool) to protected or public
Inherit A publicly; only public overloads of foo will be inherited
Change the name of A::foo(int, bool) so that the using declaration does not attempt to bring it into scope
This is a small, private project, and besides, that overload is only called inside A. So fixing the problem is a non-issue here. (I'm just going to rename the private overload.)
But it doesn't feel like it should be necessary. Why does the using declaration attempt to bring the non-accessible methods into scope? Is this particular case just not covered by the standard? Is there a way to fix this besides the methods I listed?
You can also redefine the overload you want and have it forward its argument to the function in A:
class B : private A
{
public:
void foo(int arg) { A::foo(arg); }
};
The using declaration is just too blunt a tool in this case. It brings function names into the derived class scope. And when the name refers to something private, it chokes. It can't distinguish overloads. The standard requires the names introduced by a using declaration to be accessible:
[namespace.udecl]/17
In a using-declarator that does not name a constructor, all members of
the set of introduced declarations shall be accessible. In a
using-declarator that names a constructor, no access check is
performed. In particular, if a derived class uses a using-declarator
to access a member of a base class, the member name shall be
accessible. If the name is that of an overloaded member function, then
all functions named shall be accessible. The base class members
mentioned by a using-declarator shall be visible in the scope of at
least one of the direct base classes of the class where the
using-declarator is specified.
The forwarding function can also be templated. So one won't need to redefine each function they want to expose individually.
class B : private A
{
public:
template<typename ...Args>
void foo(Args ...args) { A::foo(args...); }
};
It's "catch-all" like the using declaration, except the access specifier is checked only on template instantiation, i.e. when the function is called. So the template will be ill-formed based on its scope and whether or not the member in A is accessible there.
I found the following extract from Scott Meyer's Effective C++ which is related to your predicament (with emphasis added):
Item 33: Avoid hiding inherited names.
...
This means that if you inherit from a base class with overloaded functions
and you want to redefine or override only some of them, you need
to include a using declaration for each name you’d otherwise be hiding.
If you don’t, some of the names you’d like to inherit will be hidden.
...
It’s conceivable that you sometimes won’t want to inherit all the functions
from your base classes. Under public inheritance, this should
never be the case, because, again, it violates public inheritance’s is-a
relationship between base and derived classes. (That’s why the using
declarations above are in the public part of the derived class: names
that are public in a base class should also be public in a publicly
derived class.)
Under private inheritance, however, it can
make sense. For example, suppose Derived privately inherits from
Base, and the only version of the function that Derived wants to inherit is the
one taking no parameters. A using declaration won’t do the trick here,
because a using declaration makes all inherited functions with a given
name visible in the derived class.
No, this is a case for a different technique, namely, a simple forwarding function:
class Base {
public:
virtual void mf1() = 0;
virtual void mf1(int);
... // as before
};
class Derived: private Base {
public:
virtual void mf1() // forwarding function; implicitly
{
Base::mf1(); } // inline
};
}
I think i'm aware of accessibilty but I'm not sure if I understand visibility very clearly
For example:
class X
{
int x;
};
Here, 'x' is only visible in class and but accessible outside of class. If I'm correct, Can someone explain the text in that answer about how visibility is not controlled etc..?
(C++03/11.0) It should be noted that it is access to members and base classes that
is controlled, not their visibility. Names of members are still
visible, and implicit conversions to base classes are still
considered, when those members and base classes are inaccessible. The
interpretation of a given construct is established without regard to
access control. If the interpretation established makes use of
inaccessible member names or base classes, the construct is
ill-formed.
Perhaps this example helps:
class Bob
{
private:
int foo(int, int);
};
class David : Bob
{
void goo() {
int a = foo(1, 2); // #1
}
};
class Dani : Bob
{
void foo();
void goo() {
int a = foo(1, 2); // #2
}
};
On line #1, the name foo is visible, but the function which it names is not accessible (on account of being private to Bob). This is a compilation error, but the compiler knows that there is a potential function Bob::foo that would match, but isn't accessible.
On line #2, the name foo only refers to Dani::foo, while Bob::foo is not visible (because it is hidden), and so there is simply no matching function for the call foo(1, 2). This is also a compilation error, but this time the error is that there is no matching function at all for the call.
C++ has some esoteric feature concerning private class member names visibility and accessibility. By definition, a private class member name is only accessible by the class members and friends. However the rule of visibility can confuse many. They can be summarized as follows.
A private member's name is only accessible to other members and friends.
A private member is visible to all code that sees the class's definition. This means that its parameter types must be declared even if they can never be needed in this translation unit...
Overload resolution happens before accessibility checking.
In C++ today ("C++03" and earlier variants), the notions of accessibility and visibility are
independent. Members of classes and namespaces are visible whenever they are "in
scope" and there is no mechanism to reduce this visibility from the point of declaration.
Accessibility is only a parameter for class members and is orthogonal to the notion of
visibility. This latter observation is frequently surprising to novice C++ programmers. See this PDF.
Consider the following example.
#include < complex>
class Calc
{
public:
double Twice( double d );
private:
int Twice( int i );
std::complex Twice( std::complex c );
};
int main()
{
Calc c;
return c.Twice( 21 ); // error, Twice is inaccessible
}
When the compiler has to resolve the call to a function, it does three main things, in order:
Before doing anything else, the compiler searches for a scope that
has at least one entity named Twice and makes a list of candidates.
In this case, name lookup first looks in the scope of Calc to see if
there is at least one function named Twice; if there isn't, base
classes and enclosing namespaces will be considered in turn, one at a
time, until a scope having at least one candidate is found. In this
case, though, the very first scope the compiler looks in already has
an entity named Twice — in fact, it has three of them, and so that
trio becomes the set of candidates. (For more information about name
lookup in C++, with discussion about how it affects the way you
should package your classes and their interfaces
Next, the compiler performs overload resolution to pick the unique
best match out of the list of candidates. In this case, the argument
is 21, which is an int, and the available overloads take a double, an
int, and a complex. Clearly the int parameter is the best match for
the int argument (it's an exact match and no conversions are
required), and so Twice(int) is selected.
Finally, the compiler performs accessibility checking to determine
whether the selected function can be called.
Note that accessibility (defined by modifiers in C++) and visibility are independent. Visibility is based on the scoping rules of C++. A class member can be visible and inaccessible at the same time.
Static members as an example are visible globally through out the running of your application but accessible only with regard to the modifier applied to them.
As a note: when you declare a class, the scope is private by default (opposed to a struct where members are public by default.)
The variable member 'x' is only accessible by your class and its friends. No one else can ever access 'x' directly (it can indirectly if you have a function returning a reference to it, which is a really bad idea.)
The text you quoted talks about visibility to the compiler, so X::x exists, no matter what. It won't disappear just because it's private. The visibility is used to find the member you are referencing and the first that matches is returned. At that point the compiler checks the accessibility, if accessible, you're all good. If not it is ill-formed.
Note that I mentioned friends. That keyword makes all variable members accessible. When the compiler deals with a friends, it completely ignores all the protected and private keywords.
In most cases, that's a very easy process. It goes in order. Period.
Where it becomes more complicated is when you start using virtual functions: these can be made public, protected, and private and that can change depending on the class declaration... (A derives from B and makes a protected virtual function public; it's generally not a good idea, but C++ doesn't prevent you from doing so.) Of course this only applies to functions, not variable members, so that's a different subject.
That accessability and visibility are independet confuses especially in such situations:
class A
{
public:
void Foo(int i){
}
};
class B : public A
{
private:
void Foo(){
}
};
int main(){
B b{};
b.Foo(12);
}
Programmers from other languages would expect that A::Foo(int) would be callable because it is public. The point here is, that the private B::Foo hides the inherited proc.
This can be solved with a using declaration using A::Foo. But it becomes really hard in this sitation:
class A
{
public:
void Foo(int i){
}
};
class B : public A
{
public:
using A::Foo;
private:
void Foo(){
}
};
class C : public B
{
public:
using B::Foo;
private:
void Foo(char c){
}
}
int main(){
B b{};
b.Foo(12);
}
Using requires that there is NO private function. AFAIK the best way to solve it is to use some prefixes / suffixes for private or protected functions (like do_XXX() or do_XXX_internal).
In the STL private members are usually prefixed by a single underscore (these are reserved identifiers).
Typically the 'using' declaration is used to bring into scope some member functions of base classes that would otherwise be hidden. From that point of view it is only a mechanism for making accessible information more convenient to use.
However: the 'using' declaration can also be used to change access constraints (not only for functions but also for attributes). For example:
class C{
public:
int a;
void g(){ cout << "C:g()\n"; }
C() : a(0){}
};
class D : public C{
private:
using C::a;
using C::g;
public:
D() { a = 1; }
};
int main(void){
D d;
cout << d.a << endl; //error: a is inaccessible
C *cp = &d;
cout << cp->a << endl; //works
d.g(); //error: g is inaccessible
cp->g(); //works
return 0;
}
I think this limitation of access in the derived class is actually of no use, because you can always access g() and a from a pointer to the base class. So should't there be at least some kind of compiler warning? Or wouldn't it been even better to forbid such limitation of access by a derived class? The using declaration is not the only possibility to add constraints to access. It could also be done via overriding a base class' function an placing it in a section with more access constraints.
Are there some reasonable examples where it is indeed nessecary to limit access in such a way? If not I don't see why it should be allowed.
And another thing: at least with g++ the same code compiles well without the word 'using'. That means for the example above: it's possible to write C::a; and C::g; instead of using C::a; using C::g; Is the first only a shortcut for the latter or are there some subtle differences?
//EDIT:
so from the discussion and answers below my conclusion would be:
- it's allowed to limit access constraints in derived classes with public inheritance
- there are useful examples where it could be used
- it's use might cause problem in combination with templates (e.g. a derived class could not be a valid parameter for some template class/function any more although it's base is)
- a cleaner language design should not allow such use
- compiler could at least issue some kind of warning
With regard to your declaration without using: These are called "access declarations", and are deprecated. Here is the text from the Standard, from 11.3/1:
The access of a member of a base class can be changed in the derived class by mentioning its qualified-id in
the derived class declaration. Such mention is called an access declaration. The effect of an access declaration qualified-id; is defined to be equivalent to the declaration usingqualified-id; [Footnote: Access declarations are deprecated; member using-declarations (7.3.3) provide a better means of doing the same things. In earlier versions of the C++ language, access declarations were more limited; they were generalized and made equivalent to using-declarations - end footnote]
I would say that most often it's not good to change public members to private or protected members in the derived class, because this will violate the substitution principle: You know a base class has some functions, and if you cast to a derived class then you expect those functions to be callable too, because the derived class is-a base. And like you already mentioned, this invariant is already enforced anyway by the language allowing to convert (which working implicitly!) to a base class reference, or qualifying the function name, and then calling the (then public) function.
If you want to forbid someone calling a set of functions of the base, then i think this hints that containment (or in rare cases, private inheritance) is a better idea.
While the using declaration you showed does provide a mechanism to change access level (but only down), that is not the primary use of it in such a context. A using context there is primarily intended to allow access to functions that would otherwise be shadowed from the base class due to the language mechanics. E.g.
class A {
public:
void A();
void B();
};
class B {
public:
using A::B;
void B(int); //This would shadow A::B if not for a using declaration
};
The declaration
using C::a
brings "a" to the local naming scope so that you can later use "a" to refere to "C::a"; since that, "C::a" and "a" are interchangeable as long as you don't declare a local variable with name "a".
The declaration does not change access rights; you can access "a" in the subclass only because "a" is not private.