Private using declaration of base constructor is not private - c++

The using declaration for the base constructor is private, but the class can still be constructed. Why?
Accessibility works differently for the operator[]'s using declaration which must be public.
#include <vector>
template<typename T>
class Vec : std::vector<T>
{
private:
using std::vector<T>::vector; // Works, even if private. Why?
public:
using std::vector<T>::operator[]; // must be public
};
int main(){
Vec<int> vec = {2, 2};
auto test = vec[1];
}
What if I wanted the constructor to be private? Could it be done with a using declaration?

Using-declarations for base class constructors keep the same accessibility as the base class, regardless of the accessibility of the base class. From [namespace.udecl]:
A synonym created by a using-declaration has the usual accessibility for a member-declaration. A using-declarator that names a constructor does not create a synonym; instead, the additional constructors are accessible if they would be accessible when used to construct an object of the corresponding base class, and the accessibility of the using-declaration is ignored
emphasis added
In plain English, from cppreference:
It has the same access as the corresponding base constructor.
If you want the "inherited" constructors to be private, you have to manually specify the constructors. You cannot do this with a using-declaration.

using reference states that an inherited constructor
has the same access as the corresponding base constructor.
It further gives some hint on the rationale behind this:
It is constexpr if the user-defined constructor would have satisfied constexpr constructor requirements. It is deleted if the corresponding base constructor is deleted or if a defaulted default constructor would be deleted
Apparently, you cannot explicitly constexpr or delete an inherited constructor, so those characteristics are simply inherited. Same goes for access levels.

Related

What is the difference between constructor "=default" and the compiler generated constructor in C++?

Example for code:
class Dog
{
private:
int x;
public:
Dog()=default;
};
Vs. this code:
class Dog
{
private:
int x;
};
What is the difference between the constructor that is "=default" (the first code) and the constructor that the compiler creates (like the second code)?
Dog() = default; is a user declared constructor (not to be confused with a user defined constructor). It is a defaulted default constructor. Typically you would use it when the class has other constructors but you still want the compiler to generate a default constructor (or rather a "defaulted default constructor". This is C++ terminology at its best. Note how the two "default"s have slightly different meaning).
A user declared constructor prevents a class from being an aggregate. From cppreference, only for C++20:
An aggregate is one of the following types:
array type
class type (typically, struct or union), that has
no private or protected direct non-static data members
no user-declared or inherited constructors
no virtual, private, or protected base classes
no virtual member functions
As an example, consider:
#include <iostream>
#include <type_traits>
class Dog {
int x;
public:
Dog()=default;
};
class Horse {
int x;
};
class Swan {
public:
int x;
};
class Cow {
public:
int x;
Cow() = default;
};
int main() {
std::cout << std::is_aggregate_v<Dog>;
std::cout << std::is_aggregate_v<Horse>;
std::cout << std::is_aggregate_v<Swan>;
std::cout << std::is_aggregate_v<Cow>;
}
Output
0010
The first two, Dog and Horse, resemble your two versions of Dog. They are not aggregates, because they have private members. Swan is an aggregate, but Cow is not, because it has a user declared constructor.
Something that works with aggregates, but not with non-aggregates, is designated initializers (same cppreference page):
Swan s{.x=3}; // OK
Cow c{.x=4}; // Error: Cow is not an aggregate
TL;DR: I am not aware of a difference between your two Dogs, but in general the presence of a user declared constructor can make a difference.
I'll limit the scope to a default constructor, as in the question's code and tag. For the most part, you'll get the same effect since = default; loosely means "give me the compiler-generated one". It's important to note what exactly having no declaration does:
If there is
no user-declared constructor for class X, a non-explicit constructor having no parameters is implicitly declared
as defaulted. An implicitly-declared default constructor is an inline public member of its class.
If your declaration changes any of these, it will no longer be the exact same as the implicit one. In the standard, Dog() = default; is a user-declared constructor, but not a user-provided constructor. There are a couple small differences between having a user-declared default constructor and having no constructor.
As mentioned, aggregates were fixed:
struct not_agg {
not_agg() = delete;
int x;
};
Before the fix, such a class could be created via aggregate initialization: not_agg{}. Naturally, this also extends to = default;. Per [dcl.init.aggr]:
An aggregate is an array or a class with
no user-declared or inherited constructors
There is also rationale given for this change in annex C:
Remove potentially error-prone aggregate initialization which may apply notwithstanding the
declared constructors of a class.
An interesting, but very tiny difference is that a class with a user-declared constructor is not allowed to have non-static data members of the same name as the class:
class c {
int c; // Okay
};
class c2 {
c2() = default;
int c2; // Error
};
This is due to [class.mem]/21:
In addition, if class T has a user-declared constructor, every non-static data member of class T shall have a name different from T.
Default declared constructors can be guarded with protected or private access. Not declared default constructors are always inline public members of their classes.
= default constructors are instantiated like usual member functions, may be inline or not, they have strong linkage references in the second case. The compiler creates not declared default constructors as inline member functions with weak linkage references.
As mentioned in the comments, =default constructors are user-defined constructors and their classes are not aggregate types.

using statement and protected constructor [duplicate]

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.

Caveat with C++11 inherited constructor

https://en.wikipedia.org/wiki/C++11#Object_construction_improvement
For base-class constructors, C++11 allows a class to specify that base
class constructors will be inherited. Thus, the C++11 compiler will
generate code to perform the inheritance and the forwarding of the
derived class to the base class. This is an all-or-nothing feature:
either all of that base class's constructors are forwarded or none of
them are. Also, restrictions exist for multiple inheritance, such that
class constructors cannot be inherited from two classes that use
constructors with the same signature. Nor can a constructor in the
derived class exist that matches a signature in the inherited base
class.
Can someone give me an example to illustrate the issue with "Nor can a constructor in the derived class exist that matches a signature in the inherited base class."?
It means that if you have constructor in the derived class whose parameter list matches the parameter list of any constructor in the base class, then that derived class' constructor is taken and hides the base class'
E.g.
struct Foo
{
Foo(){std::cout << "Foo default ctor\n";}
Foo(int){std::cout << "Foo(int)\n";}
};
struct Bar : Foo
{
using Foo::Foo;
Bar(int){std::cout << "Bar\n";} // won't implicitly call Foo(int)
};
int main()
{
Bar b(1);
}
From §12.9/3 [class.inhctor] (Emphasis mine):
For each non-template constructor in the candidate set of inherited constructors other than a constructor
having no parameters or a copy/move constructor having a single parameter, a constructor is implicitly
declared with the same constructor characteristics unless there is a user-declared constructor with the same
signature in the complete class where the using-declaration appears or the constructor would be a default,
copy, or move constructor for that class.

c++ Inheriting private copy constructor: how doesn't this yield a compile time error?

In C++, if we have this class
class Uncopyable{
public:
Uncopyable(){}
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
and then we have a derived class
class Dervied: private Uncopyable{
};
My question is: why won't this generate a compile time error when the compiler generates the default copy constructor and assignment operators in the derived class ? Won't the generated code try to access base class private members ?
C++11 12.8/7 states "If the class definition does not explicitly declare a copy constructor, one is declared implicitly." so Dervied has an implicitly declared copy constructor. 12.8/11 says:
An implicitly-declared copy/move constructor is an inline public member of its class. A defaulted copy/move constructor for a class X is defined as deleted (8.4.3) if X has:
a variant member with a non-trivial corresponding constructor and X is a union-like class,
a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,
any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor,
for the copy constructor, a non-static data member of rvalue reference type, or
for the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.
Specifically, the third bullet applies: Dervied has a direct base class Uncopyable that cannot be copied because overload resolution results in a function that is inaccessible from Dervied::Dervied(const Dervied&). As a result Dervied's implicitly declared copy constructor is declared as deleted, resulting in a compile time error if and only if that copy constructor is called.
why won't this generate a compile time error when the compiler generates the default copy constructor and assignment operators in the derived class ?
Because the compiler generates them only when they are needed by the code being compiled. Write some code using the derived class where the copy constructor and/or assignment operator are involved, and you will see the compile-time error you are looking for.
The private in the inheritance makes them private to Derived, it can still see them, classes that use Derived can't.
The derived class will inherit the private copy constructor but will not need to use it unless you copy an object of derived type, as in this example.
The compiler does not auto-generate constructors/operators unless they are used and no other constructor/operator can be used to do that operation (i.e. a copy operation can be used in some situations where a move operation would suffice). The latter statement results in the following set of rules.
Here are the rules to the auto-generation of certain member functions:
Default constructor (if no other constructor is explicitly declared)
Copy constructor if no move constructor or move assignment operator
is explicitly declared. If a destructor is declared generation of a
copy constructor is deprecated.
Move constructor if no copy
constructor, move assignment operator or destructor is explicitly
declared.
Copy assignment operator if no move constructor or move assignment
operator is explicitly declared. If a destructor is declared
generation of a copy assignment operator is deprecated.
Move assignment operator if no copy constructor, copy assignment operator
or destructor is explicitly declared.
Destructor
The list is taken from this Wikipedia page.
One class cannot call private methods on another class, but it can inherit as much as it is coded too. This code just includes the member functions from Uncopyable in Derived.
Imagine if you wrote a class inheriting from std::vector. You can still erase, insert, push_back and do all those sorts of things. Because these are all public or protected vector member functions, they in turn call implementation specific private functions that do the low level things like manage memory. Your code in this derived class couldn't call those memory management functions directly though. This is used to insure the creators of the vector can change the internal details freely without breaking your use of the class.
If your example is what the code actually looks like, then this it is a common pattern used to make things that cannot be copied. It would make code like the following produce a compiler error:
Derived Foo;
Derived Bar;
Foo = Bar
It would also make the code throw an error on the following:
int GetAnswer(Derived bar)
{ /* Do something with a Derived */ }
Derived Foo;
int answer = GetAnser(Foo);
This example fails because a copy of foo is made and passed as the parameter in the function GetAnswer.
There are many reasons why something might not be copyable. The most common I have experienced is that the object manages some low level resource a single file, an opengl context, an audio output, etc... Imagine if you had a class that managed a log file. If it closed the file in the deconstructor, what happens to the original when a copy is destroyed.
Edit: to pass an Uncopyable class to a function, pass it by reference. The Following function does not make a copy:
int GetAnswer(Derived& bar)
{ /* Do something with a Derived */ }
Derived Foo;
int answer = GetAnser(Foo);
It would also cause a compiler error if all the constructor were private and the class was instantiated. But even if all the member function even constructors were private and the class was never instantiated that would be valid compiling code.
Edit: The reason a class with constructor is that there maybe other way to construct it or it maybe have static member functions, or class functions.
Sometimes factories are used to build object which have no obvious constructor. These might have functions to whatever magic is required to make the umakeable class instance. The most common I have seen is just that there was another constructor that was public, but not in an obvious place. I have also seen factories as friend classes to the unconstructable class so they could call the constructors and I have seen code manually twiddle bits of memory and cast pointers to the memory it to an instance of a class. All of these patterns are used to insure that a class is correctly created beyond just the guarantees C++ supplies.
A more common pattern I have seen is static member functions in classes.
class uncreateable
{
uncreateable() {}
public:
static int GetImportantAnswer();
};
Looking at this it can be seen that not only do I not need to create a instance of the class to call GetImportantAnswer() but I couldn't create an instance if I wanted. I could call this code using the following:
int answer;
answer = uncreateable::GetImportantAnswer();
Edit: Spelling and grammar
Well, actually this program does not compile with g++:
#include <iostream>
using namespace std;
class Uncopyable{
public:
Uncopyable(){}
~Uncopyable(){}
private:
Uncopyable(const Uncopyable&) {cout<<"in parent copy constructor";}
Uncopyable& operator=(const Uncopyable&) { cout << "in parent assignment operator";}
};
class Derived: private Uncopyable{
};
int main() {
Derived a;
Derived b = a;
}
compiler output:
$ g++ 23183322.cpp
23183322.cpp:10:88: warning: control reaches end of non-void function [-Wreturn-type]
Uncopyable& operator=(const Uncopyable&) { cout << "in parent assignment operator";}
^
23183322.cpp:13:7: error: base class 'Uncopyable' has private copy constructor
class Derived: private Uncopyable{
^
23183322.cpp:9:5: note: declared private here
Uncopyable(const Uncopyable&) {cout<<"in parent copy constructor";}
^
23183322.cpp:19:15: note: implicit copy constructor for 'Derived' first required here
Derived b = a;
^
1 warning and 1 error generated.

MSVC9.0 bug or misunderstanding of virtual inheritance and friends?

consider the following code:
class A
{
friend class B;
friend class C;
};
class B: virtual private A
{
};
class C: private B
{
};
int main()
{
C x; //OK default constructor generated by compiler
C y = x; //compiler error: copy-constructor unavailable in C
y = x; //compiler error: assignment operator unavailable in C
}
The MSVC9.0 (the C++ compiler of Visual Studio 2008) does generate the default constructor but is unable to generate copy and assignment operators for C although C is a friend of A. Is this the expected behavior or is this a Microsoft bug? I think the latter is the case, and if I am right, can anyone point to an article/forum/... where this issue is discussed or where microsoft has reacted to this bug. Thank you in advance.
P.S. Incidentally, if BOTH private inheritances are changed to protected, everything works
P.P.S. I need a proof, that the above code is legal OR illegal. It was indeed intended that a class with a virtual private base could not be derived from, as I understand. But they seem to have missed the friend part. So... here it goes, my first bounty :)
The way I interpret the Standard, the sample code is well-formed. (And yes, the friend declarations make a big difference from the thing #Steve Townsend quoted.)
11.2p1: If a class is declared to be a base class for another class using the private access specifier, the public and protected members of the base class are accessible as private members of the derived class.
11.2p4: A member m is accessible when named in class N if
m as a member of N is public, or
m as a member of N is private, and the reference occurs in a member or friend of class N, or
m as a member of N is protected, and the reference occurs in a member or friend of class N, or in a member or friend of a class P derived from N, where m as a member of P is private or protected, or
there exists a base class B of N that is accessible at the point of reference, and m is accessible when named in class B.
11.4p1: A friend of a class is a function or class that is not a member of the class but is permitted to use the private and protected member names from the class.
There are no statements in Clause 11 (Member access control) which imply that a friend of a class ever has fewer access permissions than the class which befriended it. Note that "accessible" is only defined in the context of a specific class. Although we sometimes talk about a member or base class being "accessible" or "inaccessible" in general, it would be more accurate to talk about whether it is "accessible in all contexts" or "accessible in all classes" (as is the case when only public is used).
Now for the parts which describe checks on access control in automatically defined methods.
12.1p7: An implicitly-declared default constructor for a class is implicitly defined when it is used to create an object of its class type (1.8). The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with an empty mem-initializer-list (12.6.2) and an empty function body. If that user-written default constructor would be ill-formed, the program is ill-formed.
12.6.2p6: All sub-objects representing virtual base classes are initialized by the constructor of the most derived class (1.8). If the constructor of the most derived class does not specify a mem-initializer for a virtual base class V, then V's default constructor is called to initialize the virtual base class subobject. If V does not have an accessible default constructor, the initialization is ill-formed.
12.4p5: An implicitly-declared destructor is implicitly defined when it is used to destroy an object of its class type (3.7). A program is ill-formed if the class for which a destructor is implicitly defined has:
a non-static data member of class type (or array thereof) with an inaccessible destructor, or
a base class with an inaccessible destructor.
12.8p7: An implicitly-declared copy constructor is implicitly defined if it is used to initialize an object of its class type from a copy of an object of its class type or of a class type derived from its class type. [Note: the copy constructor is implicitly defined even if the implementation elided its use (12.2).] A program is ill-formed if the class for which a copy constructor is implicitly defined has:
a nonstatic data member of class type (or array thereof) with an inaccessible or ambiguous copy constructor, or
a base class with an inaccessible or ambiguous copy constructor.
12.8p12: A program is ill-formed if the class for which a copy assignment operator is implicitly defined has:
a nonstatic data member of const type, or
a nonstatic data member of reference type, or
a nonstatic data member of class type (or array thereof) with an inaccessible copy assignment operator, or
a base class with an inaccessible copy assignment operator.
All these requirements mentioning "inaccessible" or "accessible" must be interpreted in the context of some class, and the only class that makes sense is the one for which a member function is implicitly defined.
In the original example, class A implicitly has public default constructor, destructor, copy constructor, and copy assignment operator. By 11.2p4, since class C is a friend of class A, all those members are accessible when named in class C. Therefore, access checks on those members of class A do not cause the implicit definitions of class C's default constructor, destructor, copy constructor, or copy assignment operator to be ill-formed.
Your code compiles fine with Comeau Online, and also with MinGW g++ 4.4.1.
I'm mentioning that just an "authority argument".
From a standards POV access is orthogonal to virtual inheritance. The only problem with virtual inheritance is that it's the most derived class that initializes the virtually-derived-from class further up the inheritance chain (or "as if"). In your case the most derived class has the required access to do that, and so the code should compile.
MSVC also has some other problems with virtual inheritance.
So, yes,
the code is valid, and
it's an MSVC compiler bug.
FYI, that bug is still present in MSVC 10.0. I found a bug report about a similar bug, confirmed by Microsoft. However, with just some cursory googling I couldn't find this particular bug.
Classes with virtual private base should not be derived from, per this at the C++ SWG. The compiler is doing the right thing (up to a point). The issue is not with the visibility of A from C, it's that C should not be allowed to be instantiated at all, implying that the bug is in the first (default) construction rather than the other lines.
Can a class with a private virtual base class be derived from?
Section: 11.2 [class.access.base]
Status: NAD Submitter: Jason
Merrill Date: unknown
class Foo { public: Foo() {} ~Foo() {} };
class A : virtual private Foo { public: A() {} ~A() {} };
class Bar : public A { public: Bar() {} ~Bar() {} };
~Bar() calls
~Foo(), which is ill-formed due to
access violation, right? (Bar's
constructor has the same problem since
it needs to call Foo's constructor.)
There seems to be some disagreement
among compilers. Sun, IBM and g++
reject the testcase, EDG and HP accept
it. Perhaps this case should be
clarified by a note in the draft. In
short, it looks like a class with a
virtual private base can't be derived
from.
Rationale: This is what was intended.
btw the Visual C++ v10 compiler behaviour is the same as noted in the question. Removing virtual from the inheritance of A in B fixes the problem.