The member-seq in a class specification specifies both data and function members of the class. The syntax for the member-seq is as follows. (The syntax for a constant-expression is exactly as in C++.)
member-seq ::= [ member-seq ] member-declaration | [ member-seq ] access-specifier:
| [ member-seq ] larch-cpp-clause larch-cpp-clause ::= uses-clause | simulates-clause | depends-clause | represents-clause | invariant-clause | constraint-clause member-declaration ::= function-definition | [ decl-specifier-seq ] [ member-declarator-list ];
[ fun-spec-body ] | [ decl-qualifier-seq ] ctor-declarator;
[ fun-spec-body ] | [ decl-qualifier-seq ] special-function-declarator;
[ fun-spec-body ] | [::
] nested-name-specifier [template
] unqualified-id | using-declaration | template-declaration | spec-decl | refinement-member-decl member-declarator-list ::= member-declarator [,
member-declarator ] ... member-declarator ::= declarator [ constant-initializer ] | [ identifier ]:
constant-expression constant-initializer ::==
constant-expression access-specifier ::=public
|protected
|private
A member-seq thus consists of member-declarations,
uses-clauses, simulates-clauses, depends-clauses,
represents-clauses,
invariant-clauses, constraint-clauses, and access-specifiers.
As in C++, the access-specifiers give the accessibility
of the members specified following them up to the next access-specifier.
Recall that the default access-specifier, if none is explicitly given,
is private
.
Since usually one specifies public
function members,
it is important to remember to give an access-specifier explicitly.
Members specified with a given access must be implemented
by definitions with that access.
Besides the usual specification of public
members,
one may also specify protected
and private
members in Larch/C++.
See section 10.3 Specifying Protected and Private Interfaces
for when and how to specify protected
and private
members.
In a protected or private interface specification, some data members that are not visible in the public interface may need to be modified. To allow this modification to take place, one uses a depends-clause. See section 7.6 The Depends Clause for details on dependencies.
Invariants and constraints may also be specified anywhere a member may be specified; this is to facilitate invariants about data members, which can only be stated after such members are declared. See section 7.3 Class Invariants for details on invariants. See section 7.4 History Constraints for details on constraints.
A member-declaration can take several forms. The first implements function members. The second, with the syntax
[ decl-specifier-seq ] [ member-declarator-list ] ;
[ fun-spec-body ]
is the most common in Larch/C++.
It is commonly used to declare and specify function members.
See section 6 Function Specifications for the syntax and semantics of
a function-spec-body that is not specific to classes.
It can also be used to simply declare function members,
without giving a specification,
to declare data members, to grant friendship,
and to adjust access.
Such a declaration is implemented by a matching declaration in the code,
unless it is a spec-decl.
See section 7.11 Specifying Exposed Data Members
for cases when you might want to use declarations that are not
spec-decls to specify data members in a class.
See section 7.12 Specifying Friends for when and how to grant friendship.
However,
for simple class specifications, it is usual to only
use spec-decls and to specify function members.
To adjust access, the decl-specifier-seq are omitted
and the member-declarator-list consists of a
id-expression which contains ::
(see section 5.4 Declarators for the syntax).
This adjusts the access to names inherited from base classes
(see section 7.8 Specifying Derived Classes),
and has the same meaning as in C++.
See section 11.4 of [Ellis-Stroustrup90] for details.
The third form of a member-declaration is used to declare, and optionally specify, a constructor for a class. See section 7.2.1 Constructors for more discussion and examples.
The fourth form is a using-declaration. This can also be used to adjust access to inherited members. See Section r.3.1 of [Stroustrup95] for details. See section 5.5 C++ Namespace and Using Declarations for the syntax of using-declaration.
See section 9.1 Ghost Variables for the syntax and semantics of spec-decl.
See section 10.6 Nested Refinement for the syntax and semantics of a refinement-member-decl.
In the syntax of a member-declarator,
the use of a colon (:
) followed by a constant-expression
is for specifying a C++ bit-field
(see section 9.6 of [Ellis-Stroustrup90]).
It would only be used in a class specification
to record a detailed design decision.
Inside the specification of a member function,
data members are considered to be in scope.
Thus they do not need to be made explicitly made visible
with an extern
declaration (see section 6.7 Global Variables),
as was done in early versions of Larch/C++.
If you specify the abstract values of a class explicitly,
by giving a LSL trait that has a sort with the same name as the class,
then you may not be able to
refer to data members through self
.
For example, if you specify a class Counter
with a public data member count
,
but you also explicitly use a trait that describes the abstract values
of Counter
instead of letting Larch/C++ automatically construct
the trait for you,
then you can only write self^.count
in a member function
specification if your trait has a trait function __.count
defined on the abstract values.
On the other hand, you could still use an invariant
to specify a relationship between your data member and parts of the
abstract values you specified.
See section 7.11 Specifying Exposed Data Members for an example.
The subsections below describe some details of various member specifications.
Go to the first, previous, next, last section, table of contents.