Skip to content

Commit 3542eed

Browse files
authored
Merge pull request MicrosoftDocs#2591 from mikeblome/mb-constructors
new content for extended aggregate initialization
2 parents 8ddd7c1 + 6aa0ee2 commit 3542eed

File tree

3 files changed

+50
-10
lines changed

3 files changed

+50
-10
lines changed

docs/cpp/constructors-cpp.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
title: "Constructors (C++)"
3-
ms.date: "11/19/2019"
3+
ms.date: "12/27/2019"
44
helpviewer_keywords: ["constructors [C++]", "objects [C++], creating", "instance constructors"]
55
ms.assetid: 3e9f7211-313a-4a92-9584-337452e061a9
66
---
@@ -469,6 +469,52 @@ If a constructor throws an exception, the order of destruction is the reverse of
469469
470470
1. If the constructor is non-delegating, all fully-constructed base class objects and members are destroyed. However, because the object itself is not fully constructed, the destructor is not run.
471471
472+
## <a name="extended_aggregate"></a> Derived constructors and extended aggregate initialization
473+
474+
If the constructor of a base class is non-public, but accessible to a derived class, then under **/std:c++17** mode in Visual Studio 2017 and later you can't use empty braces to initialize an object of the derived type.
475+
476+
The following example shows C++14 conformant behavior:
477+
478+
```cpp
479+
struct Derived;
480+
481+
struct Base {
482+
friend struct Derived;
483+
private:
484+
Base() {}
485+
};
486+
487+
struct Derived : Base {};
488+
489+
Derived d1; // OK. No aggregate init involved.
490+
Derived d2 {}; // OK in C++14: Calls Derived::Derived()
491+
// which can call Base ctor.
492+
```
493+
494+
In C++17, `Derived` is now considered an aggregate type. It means that the initialization of `Base` via the private default constructor happens directly, as part of the extended aggregate initialization rule. Previously, the `Base` private constructor was called via the `Derived` constructor, and it succeeded because of the friend declaration.
495+
496+
The following example shows C++17 behavior in Visual Studio 2017 and later in **/std:c++17** mode:
497+
498+
```cpp
499+
struct Derived;
500+
501+
struct Base {
502+
friend struct Derived;
503+
private:
504+
Base() {}
505+
};
506+
507+
struct Derived : Base {
508+
Derived() {} // add user-defined constructor
509+
// to call with {} initialization
510+
};
511+
512+
Derived d1; // OK. No aggregate init involved.
513+
514+
Derived d2 {}; // error C2248: 'Base::Base': cannot access
515+
// private member declared in class 'Base'
516+
```
517+
472518
### Constructors for classes that have multiple inheritance
473519
474520
If a class is derived from multiple base classes, the base class constructors are invoked in the order in which they are listed in the declaration of the derived class:

docs/cpp/initializing-classes-and-structs-without-constructors-cpp.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ kr->add_d({ 4.5 });
131131
return { 4.5 };
132132
```
133133
134+
In **/std:c++17** mode, the rules for empty brace initialization are slightly more restrictive. See [Derived constructors and extended aggregate initialization](constructors-cpp.md#extended_aggregate).
135+
134136
## initializer_list constructors
135137
136138
The [initializer_list Class](../standard-library/initializer-list-class.md) represents a list of objects of a specified type that can be used in a constructor, and in other contexts. You can construct an initializer_list by using brace initialization:

docs/overview/cpp-conformance-improvements.md

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,46 +1235,38 @@ For more information, see [Constructors](../cpp/constructors-cpp.md#inheriting_c
12351235
12361236
[P0017R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0017r1.html)
12371237
1238-
If the constructor of a base class is non-public, but accessible to a derived class, then under **/std:c++17** mode in Visual Studio version 15.7 you can no longer use empty braces to initialize an object of the derived type.
1239-
1238+
If the constructor of a base class is non-public, but accessible to a derived class, then under **/std:c++17** mode in Visual Studio 2017 version 15.7 you can no longer use empty braces to initialize an object of the derived type.
12401239
The following example shows C++14 conformant behavior:
12411240
12421241
```cpp
12431242
struct Derived;
1244-
12451243
struct Base {
12461244
friend struct Derived;
12471245
private:
12481246
Base() {}
12491247
};
12501248
12511249
struct Derived : Base {};
1252-
12531250
Derived d1; // OK. No aggregate init involved.
12541251
Derived d2 {}; // OK in C++14: Calls Derived::Derived()
12551252
// which can call Base ctor.
12561253
```
12571254

12581255
In C++17, `Derived` is now considered an aggregate type. It means that the initialization of `Base` via the private default constructor happens directly, as part of the extended aggregate initialization rule. Previously, the `Base` private constructor was called via the `Derived` constructor, and it succeeded because of the friend declaration.
1259-
12601256
The following example shows C++17 behavior in Visual Studio version 15.7 in **/std:c++17** mode:
12611257

12621258
```cpp
12631259
struct Derived;
1264-
12651260
struct Base {
12661261
friend struct Derived;
12671262
private:
12681263
Base() {}
12691264
};
1270-
12711265
struct Derived : Base {
12721266
Derived() {} // add user-defined constructor
12731267
// to call with {} initialization
12741268
};
1275-
12761269
Derived d1; // OK. No aggregate init involved.
1277-
12781270
Derived d2 {}; // error C2248: 'Base::Base': cannot access
12791271
// private member declared in class 'Base'
12801272
```

0 commit comments

Comments
 (0)