Conditional compilation directives 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Conditional compilation directives



The conditional compilation directives are used to conditionally include or exclude portions of a source file.

pp-conditional:
pp-if-section pp-elif-sectionsopt pp-else-sectionopt pp-endif

pp-if-section:
whitespaceopt # whitespaceopt if whitespace pp-expression pp-new-line conditional-sectionopt

pp-elif-sections:
pp-elif-section
pp-elif-sections pp-elif-section

pp-elif-section:
whitespaceopt # whitespaceopt elif whitespace pp-expression pp-new-line conditional-sectionopt

pp-else-section:
whitespaceopt # whitespaceopt else pp-new-line conditional-sectionopt

pp-endif:
whitespaceopt # whitespaceopt endif pp-new-line

conditional-section:
input-section
skipped-section

skipped-section:
skipped-section-part
skipped-section skipped-section-part

skipped-section-part:
skipped-charactersopt new-line
pp-directive

skipped-characters:
whitespaceopt not-number-sign input-charactersopt

not-number-sign:
Any input-character except #

As indicated by the syntax, conditional compilation directives must be written as sets consisting of, in order, an #if directive, zero or more #elif directives, zero or one #else directive, and an #endif directive. Between the directives are conditional sections of source code. Each section is controlled by the immediately preceding directive. A conditional section may itself contain nested conditional compilation directives provided these directives form complete sets.

A pp-conditional selects at most one of the contained conditional-sections for normal lexical processing:

· The pp-expressions of the #if and #elif directives are evaluated in order until one yields true. If an expression yields true, the conditional-section of the corresponding directive is selected.

· If all pp-expressions yield false, and if an #else directive is present, the conditional-section of the #else directive is selected.

· Otherwise, no conditional-section is selected.

The selected conditional-section, if any, is processed as a normal input-section: the source code contained in the section must adhere to the lexical grammar; tokens are generated from the source code in the section; and pre-processing directives in the section have the prescribed effects.

The remaining conditional-sections, if any, are processed as skipped-sections: except for pre-processing directives, the source code in the section need not adhere to the lexical grammar; no tokens are generated from the source code in the section; and pre-processing directives in the section must be lexically correct but are not otherwise processed. Within a conditional-section that is being processed as a skipped-section, any nested conditional-sections (contained in nested #if...#endif and #region...#endregion constructs) are also processed as skipped-sections.

The following example illustrates how conditional compilation directives can nest:

#define Debug // Debugging on
#undef Trace // Tracing off

class PurchaseTransaction
{
void Commit() {
#if Debug
CheckConsistency();
#if Trace
WriteToLog(this.ToString());
#endif
#endif
CommitHelper();
}
}

Except for pre-processing directives, skipped source code is not subject to lexical analysis. For example, the following is valid despite the unterminated comment in the #else section:

#define Debug // Debugging on

class PurchaseTransaction
{
void Commit() {
#if Debug
CheckConsistency();
#else
/* Do something else
#endif
}
}

Note, however, that pre-processing directives are required to be lexically correct even in skipped sections of source code.

Pre-processing directives are not processed when they appear inside multi-line input elements. For example, the program:

class Hello
{
static void Main() {
System.Console.WriteLine(@"hello,
#if Debug
world
#else
Nebraska
#endif
");
}
}

results in the output:

hello,
#if Debug
world
#else
Nebraska
#endif

In peculiar cases, the set of pre-processing directives that is processed might depend on the evaluation of the pp-expression. The example:

#if X
/*
#else
/* */ class Q { }
#endif

always produces the same token stream (class Q { }), regardless of whether or not X is defined. If X is defined, the only processed directives are #if and #endif, due to the multi-line comment. If X is undefined, then three directives (#if, #else, #endif) are part of the directive set.

Diagnostic directives

The diagnostic directives are used to explicitly generate error and warning messages that are reported in the same way as other compile-time errors and warnings.

pp-diagnostic:
whitespaceopt # whitespaceopt error pp-message
whitespaceopt # whitespaceopt warning pp-message

pp-message:
new-line
whitespace input-charactersopt new-line

The example:

#warning Code review needed before check-in

#if Debug && Retail
#error A build can't be both debug and retail
#endif

class Test {...}

always produces a warning (“Code review needed before check-in”), and produces a compile-time error (“A build can’t be both debug and retail”) if the conditional symbols Debug and Retail are both defined. Note that a pp-message can contain arbitrary text; specifically, it need not contain well-formed tokens, as shown by the single quote in the word can’t.

Region directives

The region directives are used to explicitly mark regions of source code.

pp-region:
pp-start-region conditional-sectionopt pp-end-region

pp-start-region:
whitespaceopt # whitespaceopt region pp-message

pp-end-region:
whitespaceopt # whitespaceopt endregion pp-message

No semantic meaning is attached to a region; regions are intended for use by the programmer or by automated tools to mark a section of source code. The message specified in a #region or #endregion directive likewise has no semantic meaning; it merely serves to identify the region. Matching #region and #endregion directives may have different pp-messages.

The lexical processing of a region:

#region
...
#endregion

corresponds exactly to the lexical processing of a conditional compilation directive of the form:

#if true
...
#endif

Line directives

Line directives may be used to alter the line numbers and source file names that are reported by the compiler in output such as warnings and errors, and that are used by caller info attributes (§17.4.4).

Line directives are most commonly used in meta-programming tools that generate C# source code from some other text input.

pp-line:
whitespaceopt # whitespaceopt line whitespace line-indicator pp-new-line

line-indicator:
decimal-digits whitespace file-name
decimal-digits
default
hidden

file-name:
" file-name-characters "

file-name-characters:
file-name-character
file-name-characters file-name-character

file-name-character:
Any input-character except "

When no #line directives are present, the compiler reports true line numbers and source file names in its output. When processing a #line directive that includes a line-indicator that is not default, the compiler treats the line after the directive as having the given line number (and file name, if specified).

A #line default directive reverses the effect of all preceding #line directives. The compiler reports true line information for subsequent lines, precisely as if no #line directives had been processed.

A #line hidden directive has no effect on the file and line numbers reported in error messages, but does affect source level debugging. When debugging, all lines between a #line hidden directive and the subsequent #line directive (that is not #line hidden) have no line number information. When stepping through code in the debugger, these lines will be skipped entirely.

Note that a file-name differs from a regular string literal in that escape characters are not processed; the ‘\’ character simply designates an ordinary backslash character within a file-name.

Pragma directives

The #pragma preprocessing directive is used to specify optional contextual information to the compiler. The information supplied in a #pragma directive will never change program semantics.

pp-pragma:
whitespaceopt # whitespaceopt pragma whitespace pragma-body pp-new-line

pragma-body:
pragma-warning-body

C# provides #pragma directives to control compiler warnings. Future versions of the language may include additional #pragma directives. To ensure interoperability with other C# compilers, the Microsoft C# compiler does not issue compilation errors for unknown #pragma directives; such directives do however generate warnings.

Pragma warning

The #pragma warning directive is used to disable or restore all or a particular set of warning messages during compilation of the subsequent program text.

pragma-warning-body:
warning whitespace warning-action
warning whitespace warning-action whitespace warning-list

warning-action:
disable
restore

warning-list:
decimal-digits
warning-list whitespaceopt, whitespaceopt decimal-digits

A #pragma warning directive that omits the warning list affects all warnings. A #pragma warning directive the includes a warning list affects only those warnings that are specified in the list.

A #pragma warning disable directive disables all or the given set of warnings.

A #pragma warning restore directive restores all or the given set of warnings to the state that was in effect at the beginning of the compilation unit. Note that if a particular warning was disabled externally, a #pragma warning restore (whether for all or the specific warning) will not re-enable that warning.

The following example shows use of #pragma warning to temporarily disable the warning reported when obsoleted members are referenced, using the warning number from the Microsoft C# compiler.

using System;

class Program
{
[Obsolete]
static void Foo() {}

static void Main() {
#pragma warning disable 612
Foo();
#pragma warning restore 612
}
}


Basic concepts

Application Startup

An assembly that has an entry point is called an application. When an application is run, a new application domain is created. Several different instantiations of an application may exist on the same machine at the same time, and each has its own application domain.

An application domain enables application isolation by acting as a container for application state. An application domain acts as a container and boundary for the types defined in the application and the class libraries it uses. Types loaded into one application domain are distinct from the same type loaded into another application domain, and instances of objects are not directly shared between application domains. For instance, each application domain has its own copy of static variables for these types, and a static constructor for a type is run at most once per application domain. Implementations are free to provide implementation-specific policy or mechanisms for the creation and destruction of application domains.

Application startup occurs when the execution environment calls a designated method, which is referred to as the application's entry point. This entry point method is always named Main, and can have one of the following signatures:

static void Main() {...}

static void Main(string[] args) {...}

static int Main() {...}

static int Main(string[] args) {...}

As shown, the entry point may optionally return an int value. This return value is used in application termination (§3.2).

The entry point may optionally have one formal parameter. The parameter may have any name, but the type of the parameter must be string[]. If the formal parameter is present, the execution environment creates and passes a string[] argument containing the command-line arguments that were specified when the application was started. The string[] argument is never null, but it may have a length of zero if no command-line arguments were specified.

Since C# supports method overloading, a class or struct may contain multiple definitions of some method, provided each has a different signature. However, within a single program, no class or struct may contain more than one method called Main whose definition qualifies it to be used as an application entry point. Other overloaded versions of Main are permitted, however, provided they have more than one parameter, or their only parameter is other than type string[].

An application can be made up of multiple classes or structs. It is possible for more than one of these classes or structs to contain a method called Main whose definition qualifies it to be used as an application entry point. In such cases, an external mechanism (such as a command-line compiler option) must be used to select one of these Main methods as the entry point.

In C#, every method must be defined as a member of a class or struct. Ordinarily, the declared accessibility (§3.5.1) of a method is determined by the access modifiers (§10.3.5) specified in its declaration, and similarly the declared accessibility of a type is determined by the access modifiers specified in its declaration. In order for a given method of a given type to be callable, both the type and the member must be accessible. However, the application entry point is a special case. Specifically, the execution environment can access the application's entry point regardless of its declared accessibility and regardless of the declared accessibility of its enclosing type declarations.

The application entry point method may not be in a generic class declaration.

In all other respects, entry point methods behave like those that are not entry points.

Application termination

Application termination returns control to the execution environment.

If the return type of the application’s entry point method is int, the value returned serves as the application's termination status code. The purpose of this code is to allow communication of success or failure to the execution environment.

If the return type of the entry point method is void, reaching the right brace (}) which terminates that method, or executing a return statement that has no expression, results in a termination status code of 0.

Prior to an application’s termination, destructors for all of its objects that have not yet been garbage collected are called, unless such cleanup has been suppressed (by a call to the library method GC.SuppressFinalize, for example).

Declarations

Declarations in a C# program define the constituent elements of the program. C# programs are organized using namespaces (§9), which can contain type declarations and nested namespace declarations. Type declarations (§9.6) are used to define classes (§10), structs (§10.14), interfaces (§13), enums (§14), and delegates (§15). The kinds of members permitted in a type declaration depend on the form of the type declaration. For instance, class declarations can contain declarations for constants (§10.4), fields (§10.5), methods (§10.6), properties (§10.7), events (§10.8), indexers (§10.9), operators (§10.10), instance constructors (§10.11), static constructors (§10.12), destructors (§10.13), and nested types(§10.3.8).

A declaration defines a name in the declaration space to which the declaration belongs. Except for overloaded members (§3.6), it is a compile-time error to have two or more declarations that introduce members with the same name in a declaration space. It is never possible for a declaration space to contain different kinds of members with the same name. For example, a declaration space can never contain a field and a method by the same name.

There are several different types of declaration spaces, as described in the following.

· Within all source files of a program, namespace-member-declarations with no enclosing namespace-declaration are members of a single combined declaration space called the global declaration space.

· Within all source files of a program, namespace-member-declarations within namespace-declarations that have the same fully qualified namespace name are members of a single combined declaration space.

· Each class, struct, or interface declaration creates a new declaration space. Names are introduced into this declaration space through class-member-declarations, struct-member-declarations, interface-member-declarations, or type-parameters. Except for overloaded instance constructor declarations and static constructor declarations, a class or struct cannot contain a member declaration with the same name as the class or struct. A class, struct, or interface permits the declaration of overloaded methods and indexers. Furthermore, a class or struct permits the declaration of overloaded instance constructors and operators. For example, a class, struct, or interface may contain multiple method declarations with the same name, provided these method declarations differ in their signature (§3.6). Note that base classes do not contribute to the declaration space of a class, and base interfaces do not contribute to the declaration space of an interface. Thus, a derived class or interface is allowed to declare a member with the same name as an inherited member. Such a member is said to hide the inherited member.

· Each delegate declaration creates a new declaration space. Names are introduced into this declaration space through formal parameters (fixed-parameters and parameter-arrays) and type-parameters.

· Each enumeration declaration creates a new declaration space. Names are introduced into this declaration space through enum-member-declarations.

· Each method declaration, indexer declaration, operator declaration, instance constructor declaration and anonymous function creates a new declaration space called a local variable declaration space. Names are introduced into this declaration space through formal parameters (fixed-parameters and parameter-arrays) and type-parameters. The body of the function member or anonymous function, if any, is considered to be nested within the local variable declaration space. It is an error for a local variable declaration space and a nested local variable declaration space to contain elements with the same name. Thus, within a nested declaration space it is not possible to declare a local variable or constant with the same name as a local variable or constant in an enclosing declaration space. It is possible for two declaration spaces to contain elements with the same name as long as neither declaration space contains the other.

· Each blockor switch-block, as well as a for, foreach and using statement, creates a local variable declaration space for local variables and local constants. Names are introduced into this declaration space through local-variable-declarations and local-constant-declarations. Note that blocks that occur as or within the body of a function member or anonymous function are nested within the local variable declaration space declared by those functions for their parameters. Thus it is an error to have e.g. a method with a local variable and a parameter of the same name.

· Each block or switch-block creates a separate declaration space for labels. Names are introduced into this declaration space through labeled-statements, and the names are referenced through goto-statements. The label declaration space of a block includes any nested blocks. Thus, within a nested block it is not possible to declare a label with the same name as a label in an enclosing block.

The textual order in which names are declared is generally of no significance. In particular, textual order is not significant for the declaration and use of namespaces, constants, methods, properties, events, indexers, operators, instance constructors, destructors, static constructors, and types. Declaration order is significant in the following ways:

· Declaration order for field declarations and local variable declarations determines the order in which their initializers (if any) are executed.

· Local variables must be defined before they are used (§3.7).

· Declaration order for enum member declarations (§14.3) is significant when constant-expression values are omitted.

The declaration space of a namespace is “open ended”, and two namespace declarations with the same fully qualified name contribute to the same declaration space. For example

namespace Megacorp.Data
{
class Customer
{
...
}
}

namespace Megacorp.Data
{
class Order
{
...
}
}

The two namespace declarations above contribute to the same declaration space, in this case declaring two classes with the fully qualified names Megacorp.Data.Customer and Megacorp.Data.Order. Because the two declarations contribute to the same declaration space, it would have caused a compile-time error if each contained a declaration of a class with the same name.

As specified above, the declaration space of a block includes any nested blocks. Thus, in the following example, the F and G methods result in a compile-time error because the name i is declared in the outer block and cannot be redeclared in the inner block. However, the H and I methods are valid since the two i’s are declared in separate non-nested blocks.

class A
{
void F() {
int i = 0;
if (true) {
int i = 1;
}
}

void G() {
if (true) {
int i = 0;
}
int i = 1;
}

void H() {
if (true) {
int i = 0;
}
if (true) {
int i = 1;
}
}

void I() {
for (int i = 0; i < 10; i++)
H();
for (int i = 0; i < 10; i++)
H();
}
}

Members

Namespaces and types have members. The members of an entity are generally available through the use of a qualified name that starts with a reference to the entity, followed by a “.” token, followed by the name of the member.

Members of a type are either declared in the type declaration or inherited from the base class of the type. When a type inherits from a base class, all members of the base class, except instance constructors, destructors and static constructors, become members of the derived type. The declared accessibility of a base class member does not control whether the member is inherited—inheritance extends to any member that isn’t an instance constructor, static constructor, or destructor. However, an inherited member may not be accessible in a derived type, either because of its declared accessibility (§3.5.1) or because it is hidden by a declaration in the type itself (§3.7.1.2).

Namespace members

Namespaces and types that have no enclosing namespace are members of the global namespace. This corresponds directly to the names declared in the global declaration space.

Namespaces and types declared within a namespace are members of that namespace. This corresponds directly to the names declared in the declaration space of the namespace.

Namespaces have no access restrictions. It is not possible to declare private, protected, or internal namespaces, and namespace names are always publicly accessible.

Struct members

The members of a struct are the members declared in the struct and the members inherited from the struct’s direct base class System.ValueType and the indirect base class object.

The members of a simple type correspond directly to the members of the struct type aliased by the simple type:

· The members of sbyte are the members of the System.SByte struct.

· The members of byte are the members of the System.Byte struct.

· The members of short are the members of the System.Int16 struct.

· The members of ushort are the members of the System.UInt16 struct.

· The members of int are the members of the System.Int32 struct.

· The members of uint are the members of the System.UInt32 struct.

· The members of long are the members of the System.Int64 struct.

· The members of ulong are the members of the System.UInt64 struct.

· The members of char are the members of the System.Char struct.

· The members of float are the members of the System.Single struct.

· The members of double are the members of the System.Double struct.

· The members of decimal are the members of the System.Decimal struct.

· The members of bool are the members of the System.Boolean struct.

Enumeration members

The members of an enumeration are the constants declared in the enumeration and the members inherited from the enumeration’s direct base class System.Enum and the indirect base classes System.ValueType and object.

Class members

The members of a class are the members declared in the class and the members inherited from the base class (except for class object which has no base class). The members inherited from the base class include the constants, fields, methods, properties, events, indexers, operators, and types of the base class, but not the instance constructors, destructors and static constructors of the base class. Base class members are inherited without regard to their accessibility.

A class declaration may contain declarations of constants, fields, methods, properties, events, indexers, operators, instance constructors, destructors, static constructors and types.

The members of object and string correspond directly to the members of the class types they alias:

· The members of object are the members of the System.Object class.

· The members of string are the members of the System.String class.

Interface members

The members of an interface are the members declared in the interface and in all base interfaces of the interface. The members in class object are not, strictly speaking, members of any interface (§13.2). However, the members in class object are available via member lookup in any interface type (§7.4).

Array members

The members of an array are the members inherited from class System.Array.

Delegate members

The members of a delegate are the members inherited from class System.Delegate.

Member access

Declarations of members allow control over member access. The accessibility of a member is established by the declared accessibility (§3.5.1) of the member combined with the accessibility of the immediately containing type, if any.

When access to a particular member is allowed, the member is said to be accessible. Conversely, when access to a particular member is disallowed, the member is said to be inaccessible. Access to a member is permitted when the textual location in which the access takes place is included in the accessibility domain (§3.5.2) of the member.

Declared accessibility

The declared accessibility of a member can be one of the following:

· Public, which is selected by including a public modifier in the member declaration. The intuitive meaning of public is “access not limited”.

· Protected, which is selected by including a protected modifier in the member declaration. The intuitive meaning of protected is “access limited to the containing class or types derived from the containing class”.

· Internal, which is selected by including an internal modifier in the member declaration. The intuitive meaning of internal is “access limited to this program”.

· Protected internal (meaning protected or internal), which is selected by including both a protected and an internal modifier in the member declaration. The intuitive meaning of protected internal is “access limited to this program or types derived from the containing class”.

· Private, which is selected by including a private modifier in the member declaration. The intuitive meaning of private is “access limited to the containing type”.

Depending on the context in which a member declaration takes place, only certain types of declared accessibility are permitted. Furthermore, when a member declaration does not include any access modifiers, the context in which the declaration takes place determines the default declared accessibility.

· Namespaces implicitly have public declared accessibility. No access modifiers are allowed on namespace declarations.

· Types declared in compilation units or namespaces can have public or internal declared accessibility and default to internal declared accessibility.

· Class members can have any of the five kinds of declared accessibility and default to private declared accessibility. (Note that a type declared as a member of a class can have any of the five kinds of declared accessibility, whereas a type declared as a member of a namespace can have only public or internal declared accessibility.)

· Struct members can have public, internal, or private declared accessibility and default to private declared accessibility because structs are implicitly sealed. Struct members introduced in a struct (that is, not inherited by that struct) cannot have protected or protected internal declared accessibility. (Note that a type declared as a member of a struct can have public, internal, or private declared accessibility, whereas a type declared as a member of a namespace can have only public or internal declared accessibility.)

· Interface members implicitly have public declared accessibility. No access modifiers are allowed on interface member declarations.

· Enumeration members implicitly have public declared accessibility. No access modifiers are allowed on enumeration member declarations.

Accessibility domains

The accessibility domain of a member consists of the (possibly disjoint) sections of program text in which access to the member is permitted. For purposes of defining the accessibility domain of a member, a member is said to be top-level if it is not declared within a type, and a member is said to be nested if it is declared within another type. Furthermore, the program text of a program is defined as all program text contained in all source files of the program, and the program text of a type is defined as all program text contained in the type-declarations of that type (including, possibly, types that are nested within the type).

The accessibility domain of a predefined type (such as object, int, or double) is unlimited.

The accessibility domain of a top-level unbound type T (§4.4.3) that is declared in a program P is defined as follows:

· If the declared accessibility of T is public, the accessibility domain of T is the program text of P and any program that references P.

· If the declared accessibility of T is internal, the accessibility domain of T is the program text of P.

From these definitions it follows that the accessibility domain of a top-level unbound type is always at least the program text of the program in which that type is declared.

The accessibility domain for a constructed type T<A1,...,AN> is the intersection of the accessibility domain of the unbound generic type T and the accessibility domains of the type arguments A1,...,AN.

The accessibility domain of a nested member M declared in a type T within a program P is defined as follows (noting that M itself may possibly be a type):

· If the declared accessibility of M is public, the accessibility domain of M is the accessibility domain of T.

· If the declared accessibility of M is protected internal, let D be the union of the program text of P and the program text of any type derived from T, which is declared outside P. The accessibility domain of M is the intersection of the accessibility domain of T with D.

· If the declared accessibility of M is protected, let D be the union of the program text of T and the program text of any type derived from T. The accessibility domain of M is the intersection of the accessibility domain of T with D.

· If the declared accessibility of M is internal, the accessibility domain of M is the intersection of the accessibility domain of T with the program text of P.

· If the declared accessibility of M is private, the accessibility domain of M is the program text of T.

From these definitions it follows that the accessibility domain of a nested member is always at least the program text of the type in which the member is declared. Furthermore, it follows that the accessibility domain of a member is never more inclusive than the accessibility domain of the type in which the member is declared.

In intuitive terms, when a type or member M is accessed, the following steps are evaluated to ensure that the access is permitted:

· First, if M is declared within a type (as opposed to a compilation unit or a namespace), a compile-time error occurs if that type is not accessible.

· Then, if M is public, the access is permitted.

· Otherwise, if M is protected internal, the access is permitted if it occurs within the program in which M is declared, or if it occurs within a class derived from the class in which M is declared and takes place through the derived class type (§3.5.3).

· Otherwise, if M is protected, the access is permitted if it occurs within the class in which M is declared, or if it occurs within a class derived from the class in which M is declared and takes place through the derived class type (§3.5.3).

· Otherwise, if M is internal, the access is permitted if it occurs within the program in which M is declared.

· Otherwise, if M is private, the access is permitted if it occurs within the type in which M is declared.

· Otherwise, the type or member is inaccessible, and a compile-time error occurs.

In the example

public class A
{
public static int X;
internal static int Y;
private static int Z;
}

internal class B
{
public static int X;
internal static int Y;
private static int Z;

public class C
{
public static int X;
internal static int Y;
private static int Z;
}

private class D
{
public static int X;
internal static int Y;
private static int Z;
}
}

the classes and members have the following accessibility domains:

· The accessibility domain of A and A.X is unlimited.

· The accessibility domain of A.Y, B, B.X, B.Y, B.C, B.C.X, and B.C.Y is the program text of the containing program.

· The accessibility domain of A.Z is the program text of A.

· The accessibility domain of B.Z and B.D is the program text of B, including the program text of B.C and B.D.

· The accessibility domain of B.C.Z is the program text of B.C.

· The accessibility domain of B.D.X and B.D.Y is the program text of B, including the program text of B.C and B.D.

· The accessibility domain of B.D.Z is the program text of B.D.

As the example illustrates, the accessibility domain of a member is never larger than that of a containing type. For example, even though all X members have public declared accessibility, all but A.X have accessibility domains that are constrained by a containing type.

As described in §3.4, all members of a base class, except for instance constructors, destructors and static constructors, are inherited by derived types. This includes even private members of a base class. However, the accessibility domain of a private member includes only the program text of the type in which the member is declared. In the example

class A
{
int x;

static void F(B b) {
b.x = 1; // Ok
}
}

class B: A
{
static void F(B b) {
b.x = 1; // Error, x not accessible
}
}

the B class inherits the private member x from the A class. Because the member is private, it is only accessible within the class-body of A. Thus, the access to b.x succeeds in the A.F method, but fails in the B.F method.



Поделиться:


Последнее изменение этой страницы: 2016-08-10; просмотров: 193; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 54.225.21.228 (0.162 с.)