Udostępnij za pośrednictwem


Directly Derived Types

New types derived directly from existing types are types that point to, refer to, or (in the case of functions) transform type data to return a new type.

  • Arrays of Variables or Objects

  • Functions

  • Pointers of a Given Type

  • References to Objects

  • Constants

  • Pointers to Class Members

Arrays of Variables or Objects

Arrays of variables or objects can contain a specified number of a particular type. For example, an array derived from integers is an array of type int. The following code sample declares and defines an array of 10 int variables and an array of 5 objects of class SampleClass:

int         ArrayOfInt[10];
SampleClass aSampleClass[5];

Functions

Functions take zero or more arguments of given types and return objects of a specified type (or return nothing, if the function has a void return type).

Pointers of a Given Type

Pointers to variables or objects select an object in memory. The object can be global, local (or stack-frame), or dynamically allocated. Pointers to functions of a given type allow a program to defer selection of the function used on a particular object or objects until run time. The following example shows a definition of a pointer to a variable of type char:

char *szPathStr;

References to Objects

References to objects provide a convenient way to access objects by reference, but use the same syntax required to access objects by value. The following example demonstrates how to use references as arguments to functions and as return types of functions:

BigClassType &func( BigClassType &objname )
{
    objname.DoSomething();    // Note that member-of operator(.)
                              //  is used.
    objname.SomeData = 7;     // Data passed by non-const
                              //  reference is modifiable.
    return objname;
}

The important points about passing objects to a function by reference are:

  • The syntax for accessing members of class, struct, and union objects is the same as if they were passed by value: the member-of operator (.).

  • The objects are not copied prior to the function call; their addresses are passed. This can reduce the overhead of the function call.

Additionally, functions that return a reference need only accept the address of the object to which they refer, instead of a copy of the whole object.

Although the preceding example describes references only in the context of communication with functions, references are not constrained to this use. Consider, for example, a case where a function needs to be an l-value — a common requirement for overloaded operators:

class Vector
{
public:
    Point &operator[]( int nSubscript ); // Function returns a
                                         //  reference type
};

The preceding declaration specifies a user-defined subscript operator for class Vector. In an assignment statement, two possible conditions occur:

Vector v1;
int    i;
Point p; 
v1[7] = p;   // Vector used as an l-value
p = v1[7];   // Vector used as an r-value

The latter case, where v1[7] is used as an r-value, can be implemented without use of references. However, the former case, where v1[7] is used as an l-value, cannot be implemented easily without functions that are of reference type. Conceptually, the last two statements in the preceding example translate to the following code:

v1.operator[]( 7 ) = 3;    // Vector used as an l-value
i = v1.operator[]( 7 );    // Vector used as an r-value

When viewed in this way, it is easier to see that the first statement must be an l-value to be semantically correct on the left side of the assignment statement.

For more information about overloading, and about overloaded operators in particular, see Overloaded Operators.

You can also use references to declare a const reference to a variable or object. A reference declared as const retains the efficiency of passing an argument by reference, while preventing the called function from modifying the original object. Consider the following code:

// reference_to_objects2.cpp
// IntValue is a const reference.
#include <stdio.h>
void PrintInt( const int &IntValue )
{
    printf_s( "%d\n", IntValue );
}
int main()
{
}

Reference initialization is different from assignment to a variable of reference type. Consider the following code:

// reference_to_objects3.cpp
int main()
{
   int i = 7;
   int j = 5;

   // Reference initialization
   int &ri = i;  // Initialize ri to refer to i.
   int &rj = j;  // Initialize rj to refer to j.

   // Assignment
   ri = 3;       // i now equal to 3.
   rj = 12;      // j now equal to 12.
   ri = rj;      // i now equals j (12).
}

C++ Constants

See Literals for more information about the various kinds of constants allowed in C++.

Pointers to Class Members

These pointers define a type that points to a class member of a particular type. Such a pointer can be used by any object of the class type or any object of a type derived from the class type.

Use of pointers to class members enhances the type safety of the C++ language. Three new operators and constructs are used with pointers to members, as shown in the following table:

Operators and Constructs Used with Pointers to Members

Operator or

Construct

Syntax

Use

::*

type::*ptr-name

Declaration of pointer to member. The type specifies the class name, and ptr-name specifies the name of the pointer to member. Pointers to members can be initialized. For example:

 

 

MyType::*pMyType = &MyType::i;

.*

obj-name.*ptr-name

Dereference a pointer to a member using an object or object reference. For example:

 

 

int j = Object.*pMyType;

–>*

obj-ptr–>*ptr-name

Dereference a pointer to a member using a pointer to an object. For example:

 

 

int j = pObject->*pMyType;

Example

Description

Consider this example that defines a class AClass and the derived type pDAT, which points to the member I1:

Code

// pointers1.cpp
// compile with: /EHsc
#include <iostream>

using namespace std;

// Define class AClass.
class AClass
{
public:
    int I1;
    void Show() { cout << I1 << endl; }
};

// Define a derived type pDAT that points to I1 members of
// objects of type AClass.
int AClass::*pDAT = &AClass::I1;

int main()
{
    AClass aClass;             // Define an object of type AClass.
    AClass *paClass = &aClass;  // Define a pointer to that object.

    int i;

    aClass.*pDAT = 7777;     // Assign to aClass::I1 using .* operator.
    aClass.Show();

    i = paClass->*pDAT;       // Dereference a pointer 
                              //  using ->* operator.
    cout << i << "\n";
}

Output

7777
7777

The pointer to member pDAT is a new type derived from class AClass. It is more strongly typed than a plain pointer to int because it points only to int members of class AClass (in this case, I1). Pointers to static members are plain pointers rather than pointers to class members. Consider the following example:

// pointers2.cpp
class HasStaticMember
{
public:
    static int SMember;
};
int HasStaticMember::SMember = 0;

int *pSMember = &HasStaticMember::SMember;

int main()
{
}

Note that the type of the pointer is "pointer to int," not "pointer to HasStaticMember::int."

Pointers to members can refer to member functions as well as member data.

Example

Code

// pointers3.cpp
#include <stdio.h>

// Declare a base class, A, with a virtual function, Identify.
// (Note that in this context, struct is the same as class.)
struct A
{
    virtual void Identify() = 0; // No definition for class A.
};

// Declare a pointer to the Identify member function.
void (A::*pIdentify)() = &A::Identify;

// Declare class B derived from class A.
struct B : public A
{
    void Identify();
};

// Define Identify functions for classe B
void B::Identify()
{
    printf_s( "Identification is B::Identify\n" );
}

int main()
{
    B  BObject;          // Declare objects of type B
    A *pA;               // Declare pointer to type A.

    pA = &BObject;       // Make pA point to an object of type B.
    (pA->*pIdentify)();  // Call Identify function through pointer
                         //  to member pIdentify.
}

Output

Identification is B::Identify

The function is called through a pointer to type A. However, because the function is a virtual function, the correct function for the object to which pA refers is called.

See Also

Reference

Derived Types