Day 4
This is the day 4 page for object oriented programming course 102, an introduction to object oriented programming. On day 4 we're going to introducing how to write a class.Below are the topics and course materials we are learning today.
Declaring a class
A class is one of several user defined complex types, and can be declared using the following syntax.type TClassA = class end;This declares a class type identified as TClassA inheriting from TObject, the base class for all class types. To specify an inheritance you could type:
type TClassB = class(TClassA) end;This declares a class type identified as TClassB inheriting from TClassA.
Instances
A class is not the same as an object. A class can be thought of as the blueprint for an object, and an object as an instance of the class. To create an object, or an instance of a class, you can declare a variable of a type that is compatible with a class and create an object like so:var A, B: TObject; begin A := TClassA.Create; B := TClassB.Create; A.Free; B.Free; end.In the example above, we create two objects and assign them to variables which are compatible with our class types. The first variable A is assigned an instance of the TClassA type using the constructor Create in the line:
A := TClassA.Create;Note that class types are considered compatible with each of if one class inherits or descends from the other class. In our example both TClassA and TClassB are compatible with TObject because all classes inherit from TObject.
Inheritance
When a class inherits from another class it gains all of the functionality of the base class and has the opportunity to design new functionality. Functionality can either be new or overridden. As shown above a class can specify its base class in the declaration using the syntax:TCurrentClass = class(TBaseClass)Where TCurrentClass describes a new class type inheriting from an already declared TBaseClass type.
Functionality
Functionality can be added to a class declaration using fields, methods, or properties.Fields
A field is simply a variable declared inside a class as demonstrated below. Note you do not need to use the var keyword to declare a field inside a class:type TAddress = class Street: string; City: string; State: string; ZipCode: string; end;It is customary to prefix field names with the letter F to denote a field, and hide the field so that only the class you are writing can alter their values. For now our examples we will omit the letter F before a field name.
Methods
Methods are functions or procedures associated with a class. When you declare a method in a class it's required to have two parts, the declaration inside the class and the implementation located somewhere after the class declaration.Here is an example of a method on our TAddress class:
type TAddress = class Street: string; City: string; State: string; ZipCode: string; function MakeLabel(const Person: string): string; end; function TAddress.MakeLabel(const Person: string): string; const NewLine = #13; begin Result := Person + NewLine + Street + NewLine + City + ', ' + State + ' ' + ZipCode; end;In the example above we have added a MakeLabel method to our TAddress class. Not that Make label is declared in two places, once inside the class with just the method name and signature, and again after the class with the implementation of the MakeLabel method.
Note that the implementation of MakeLabel is the same as other functions you have written in the past, but it includes the name of the class in the implementation.
Properties
From all outward appearances a property seems like a field of an object. A field can be protected or have actions associated with it using properties. For examples we could rewrite our TAddress class using properties in place of fields like so:type TAddress = class private FStreet: string; FCity: string; FState: string; FZipCode: string; public function MakeLabel(const Person: string): string; property Street: string read FStreet; property City: string read FCity; property State: string read FState; property ZipCode: string read FZipCode; end;In the examples above we have changed the fields to properties. The properties each read from privately backed fields. Note that in the above class we have declared only read directives resulting in read only properties.
Reading and writing properties
A property can be declared inside a class using the following syntaxproperty PropertyName: PropertyType read GetProp write SetProp;The write portion is optional. Omitting a write directive results in a read only property. GetProp and SetProp can refer to either field names or methods of types that match PropertyType.
Consider this property declaration:
private FZipCode: string; procedure SetZipCode(const Value: string); public property ZipCode: string read FZipCode write SetZipCode; end;We could then write a method that is called anytime a ZipCode is set:
var A: TAddress; begin A := TAddress.Create; A.ZipCode := '32808'; // calls A.SetZipCode('32808'); end;We may implement SetZipCode like so:
procedure TAddress.SetZipCode(const Value: string); var C: Char; begin if Length(Value) <> 5 then begin WriteLn('ZipCode must be 5 characters'); Exit; end; for C in Value do if not (C in ['0'..'9']) then begin WriteLn('ZipCode must contain only numbers'); Exit; end; FZipCode := Value; end;
Constructors and destructors
Any class you create should be matched with a destructor. TObject includes a method to destroy an object named Free that checks if an object exists before trying to destroy it.You can define your own constructors using the constructor keyword in place of function or procedure. For example you might write:
constructor Create(const Street, City, State, ZipCode: string);And like with any method you would write the implementation somewhere below the class declaration:
constructor TAddress.Create(const Street, City, State, ZipCode: string); begin inherited Create; FStreet := Street; FCity := City; FState := State; FZipCode := ZipCode; end;