< C++ .NET Value Type 2 | Main | C++ .NET Value Type 4 >


 

 

Value Types 3

 

 

What we have in this page?

 

  1. Using One Struct Inside Another: Nested Structure

  2. Copying Structs

 

 

Using One Structure Inside Another: Nested Structure

 

It’s possible and often useful to use one struct inside another. Imagine that you have a structure named Person for describing a person. The structure contains the name and date of birth, among other data. You could use separate fields for each item, but you could also make the date entries into another struct and refer to it inside Person. Here’s an example:

// A Date structure containing day, month and year

value struct Date

{

    int dd, mm, yyyy;

};

 

// A Person structure containing a Date member

value struct Person

{

    String^ name;

    Date DOB;

};

You can see how the Date structure contains three members representing the day, month, and year. This structure is quite general, so you could use it in other programs. The Person structure contains a String reference to hold the name and a Date object to hold the date of birth.

In this exercise, you will use these two classes to investigate how structure data members work.

 

1.        Start C++/Visual Studio .NET, and create a new CLR Console Application project named Person.

 

Creating a new CLR Console Application project named Person

 

2.        At the top of the file, immediately under using namespace System;, add the previous structure definitions for Date and Person.

 

3.        In the main() function, create a Person object. Remember that you don’t use new because structures are value types.

// Create a Person

Person p1;

4.        Fill in the values for the fields.

// Fill in the name

p1.name = "Fred";

p1.DOB.dd = 11;

p1.DOB.mm = 5;

p1.DOB.yyyy = 2009;

Notice how structure data members are accessed. Because the DOB member has members of its own, you simply extend the dot notation to another level to access its members. You can continue this nesting to as many levels as you like, although it is unusual to go much deeper than you’ve done here.

You can also initialize all the members of Person in one line. Comment out the four initialization lines you entered in previous step and then amend the line where you create Person:

Person p1 = {"Fred", {11, 5, 2009}};

Can you see what is going on here? The data in the braces called an aggregate initializer provides data for the initialization of the struct. The Person struct contains two items, a String and a Date. Therefore, there are two items in the list. Because Date has members of its own, its entries are also enclosed in braces.

Use of an aggregate initializer is an alternative to using a constructor and can be useful where there’s no checking to be done on the data. If you decide that the date of birth is wrong, you can simply create a new Date and copy it into the Person object something like the following code.

 

      // Create a new Date

      Date newDOB = {7, 5, 2005};

      p1.DOB = newDOB;

 

The new Date takes the values specified in the initializer, and it is then copied into the Person object, overwriting the values in the Date already there. A complete code snippet is shown below.

// Person.cpp : main project file.

#include "stdafx.h"

using namespace System;

 

// A Date structure containing day, month and year

value struct Date

{

    int dd, mm, yyyy;

};

 

// A Person structure containing a Date member

value struct Person

{

    String^ name;

    Date DOB;

};

 

int main(array<System::String ^> ^args)

{

      // Create a Person

      // Person p1;

      Person p1 = {"Fred", {11, 5, 2009}};

      // Fill in the name

      // p1.name = "Fred";

      // p1.DOB.dd = 11;

      // p1.DOB.mm = 5;

      // p1.DOB.yyyy = 2009;

 

      // Create a new Date

      Date newDOB = {7, 5, 2005};

      p1.DOB = newDOB;

    return 0;

}

// No output

You can see the structure of the Person struct by running the program under control of the debugger.

 

5.   Place a breakpoint in the program at the line where p1 is created by clicking in the gray margin to the left of the code. You should see a red dot appear, marking an active breakpoint.

 

6.  Start the program by pressing F5. Once the program has loaded, it will execute and stop at the breakpoint. You can now use the Locals window at the bottom of the screen to look at the structure of the Person type. If the Locals window isn’t being displayed in debug mode, display it by pressing Ctrl+Alt+V followed by L.

 

7.   Click the plus sign to the left of p1 in the Locals window to expand the structure of Person. You’ll see that it has name and DOB members, and if you click the plus sign to the left of DOB, you can expand its structure as well.

 

8.    Press F10 to step through the code until all the members are initialized. You will see the members of p1 displayed in red as each value changes.

 

Local windows information during the debug process  

 

9.        When you’ve finished, press Shift+F5 to stop debugging or click the Stop Debugging button on the toolbar.

 

Finally, let’s consider nested structure definitions. If you don’t want to use the Date struct anywhere except inside your Person structure, you can define the Date structure inside the Person structure, as shown here:

// A Person structure containing a Date member

value struct Person

{

    String^ name;

    // Date DOB;

    value struct Date

    {

        int dd, mm, yyyy;

    };

    Date DOB;

};

You create Person variables and access their members exactly the same as before. The big difference is that the Date structure is now a part of Person, so you can’t create Date variables on their own.

 

Copying Structs

 

Because structs are value types, copying them makes a copy of the values they contain. Contrast this behavior with classes, where copying objects results in references being copied.

Person p1;

Person p2;

...

p2 = p1;   // p1’s data is copied into p2

MyClass m1;

MyClass m2;

...

m2 = m1;   // m2 and m1 now refer to the same object. No data is copied

You can’t use a gc reference type as a member of a struct because structs aren’t garbage collected; a reference member would have to take part in garbage collection.

 

 

 

 

Part 1 | Part 2 | Part 3 | Part 4

 


 

< C++ .NET Value Type 2 | Main | C++ .NET Value Type 4 >