Class (computer science)
From Wikipedia, the free encyclopedia
In object-oriented programming, classes are used to group related variables and functions. A class describes a collection of encapsulated instance variables and methods (functions), possibly with implementation of those types together with a constructor function that can be used to create objects of the class.
A class is a cohesive package that consists of a particular kind of compile-time metadata. It describes the rules by which objects behave; these objects are referred to as "instances" of that class. A class specifies the structure of data which each instance contains as well as the methods (functions) which manipulate the data of the object and perform tasks; such methods are sometimes described as "behavior". A method is a function with a special property that it has access to data stored in an object. A class is the most specific type of an object in relation to a specific layer. A class may also have a representation (metaobject) at run-time, which provides run-time support for manipulating the class-related metadata.
Instances of a class will have certain aspects (aka: features, attributes or properties) in common. A class 'Person' for example would describe the properties common to all instances of the 'Person' class. One of the benefits of programming with classes is that all instances of a particular class will follow the defined behaviour of the class they instantiate. Each person is generally alike; but varies in such properties as "height" and "weight". The class would list types of such instance variables; and also define, via methods, the actions which humans can perform: "run", "jump", "sleep", "throw object", etc.
[edit] Interfaces
A class can "implement" (or "realize") multiple interfaces, each of which specify one or more abstract method signatures (name and type of the method and its parameters) which must be defined (overridden) in that class.
Unlike multiple inheritance where actual code is inherited (along with naming and logical conflicts), interfacing allows us to define a behaviour-interface (methods) all implementing classes should be able to fulfill. Partial implementations of interfaces are not allowed, that is, every specified method has to have an implementation. However some languages do not require that every parameter combination needs to be supported.
Each interface of the class is associated with a type of object references referring to the interface, through which methods of objects can be invoked. Each reference points to a single instance of the class. Each reference has a lifetime, which specifies how long the reference can be used, usually bound to the time when some specific operations are invoked via the interface. It is assumed that there is a mechanism for accessing the object with a valid object reference. However, while the object reference is a reference to a specific location at any one time, over time the same object can be located at different places.
The object-oriented programming methodology is designed in such a way that the operations of any interface of a class are usually chosen to be independent of each other. This means that an interface places no requirements for clients to invoke the operations of one interface in any particular order. This approach has the benefit that client code can assume that the operations of an interface are available for use whenever the client holds a valid reference to the object. This will also result in a client-server (or layered) design where servers do not depend in any way on the clients.
The methods that are not in any of the interfaces of a class are private to the class, and not intended to be depended on by other classes.
The "set of all interfaces of a class" is sometimes called the interface of the class.
The internal data structures defined as part of a class are not considered to be part of its interface. Rather, public accessor methods can be used to inspect or alter object data. The various object-oriented programming languages enforce this to various degrees. For example, Java does not allow the programmer to access the private data of a class at all, whereas in languages like Objective-C or Perl the programmer can do what they want. In C++, private methods are visible but not accessible in the interface; however they are commonly made invisible by explicitly declaring fully abstract classes that represent the interfaces of the class.
[edit] Structure of a class
A class contains a description of structure of data ("state") stored in the objects of the class. The state of an object is stored in some resource, such as memory or a file. The storage is assumed to be located in a specific location, such that it is possible to access the object through references to the identity of the objects. However, the actual storage location associated with an object may change with time. In such situations, the identity of the object does not change. The state is encapsulated and every access to the state occurs through methods of the class. Specific data items in the state, such as xsize and ysize in the example, are sometimes called class attributes or class properties.
A class implements its interfaces by specifying methods that describe what operations can be performed on the data stored in the objects of the class. Each method specifies only tasks that are related to the stored data. Multimethods can be used when a single task requires access to many objects' data.
A class also describes a set of invariants that are preserved by every method in the class. An invariant is a constraint on the state of an object that should be satisfied by every object of the class. The main purpose of the invariants is to establish what objects belong to the class. An invariant is what distinguishes datatypes and classes from each other, that is, a class does not allow use of all possible values for the state of the object, only those that are well-defined by the semantics of the intended use of the datatype. The set of supported methods often implicitly establishes an invariant. Some programming languages support specification of invariants as part of the definition of the class, and enforce them through the type system. Encapsulation of state is necessary for being able to enforce the invariants of the class.
An implementation of a class specifies constructor and destructor functions that allow creation and destruction of objects of the class. A constructor that takes arguments can be used to create an object from data. The main purpose of a constructor is to establish the invariant of the class, failing if the invariant isn't valid. The main purpose of a destructor is to destroy the identity of the object, invalidating any references in the process. A destructor that returns a value can be used to obtain a public representation (transfer encoding) of an object of a class and simultaneously destroy the copy of the object stored in current thread's memory [If supported by the programming language used]. Constructors and destructors are also sometimes used to reserve and release resources associated with the object.
A class can also implement a set of auxiliary functions, sometimes called class functions or static methods. Static methods are often used to find, create or destroy objects of the class. Constructors and destructors are sometimes specified as static methods. Often, mechanisms for sending an object to another location or changing the class of an object are specified as static methods.
The class members can be designated as public, private or protected. The public access specifier means that all clients can access the member by its name. The private access specifier restricts the access to the class itself. The protected access specifier allows the class itself and all its subclasses to access the member. In addition, some languages, such as C++, support a mechanism where a function explicitly declared as friend of the class may access the members designated as private or protected. Access specifiers do not control visibility, in that even private members may be visible to client code. An inaccessible but visible member may be referred to at run-time (e.g. pointer to it can be returned from member functions), but all attempts to use it by referring to the name of the member from client code will be prevented by the type checker. Object-oriented design uses the access specifiers in conjunction with careful design of public method implementations to enforce class invariants. Access specifiers are intended to protect against accidental use of members by clients, but are not suitable for run-time protection of object's data. [1]
[edit] Associations between classes
In object-oriented design an association between two classes is a type of a link between the corresponding objects. A (two-way) association between classes A and B describes a relationship between each object of class A and some objects of class B, and vice versa. Associations are often named with a verb, such as "subscribes-to".
An association role describes the role of an instance of a class when the instance participates in an association. An association role is related to each end of the association. The role describes an instance of a class from the point of view of a situation in which the instance participates in the association. For example, a "subscriber" role describes instances of the class "Person" when it participates in a "subscribes-to" relationship with the class "Magazine". Also, a "Magazine" has the "subscribed magazine" role when the subscribers subscribe-to it.
Association role multiplicity describes how many instances correspond to each instance of the other class(es) of the association. Common multiplicities are "0..1", "1..1", "1..*" and "0..*", where the "*" specifies any number of instances.
There are some special kinds of associations between classes. Composition between class A and class B describes a "part-of" relationship where instances of class B have shorter lifetime than the lifetime of the corresponding instances of the enclosing class. Class B is said to be a part of class A. This is often implemented in programming languages by allocating the data storage of instances of class A to contain a representation of instances of class B. Aggregation is like composition in that it describes that instances of a class are part of instances of the other class, but the constraint on lifetime of the instances is not required. The implementation of aggregation is often via a pointer or reference to the contained instance. In both cases, method implementations of the enclosing class can invoke methods of the part class.
[edit] Local classes
In some languages, classes can be declared inside the scope of another function. This limits references to the class name to within the scope where the class is declared. Depending on the semantic rules of the language, methods of such local classes may or may not be able to access local variables of the enclosing function.
For example, in C++ a class declared within another function may refer to static variables declared within its enclosing function, but may not access the function's automatic variables. Such local classes may not declare their own static data members, and may not be used in template arguments.
[edit] Partial classes
Partial classes are classes that can be split over multiple files, making it easier to deal with large quantities of code. At compile time the partial classes are grouped together, thus logically make no difference to the output. An example of the use of partial classes may be the separation of user interface logic and processing logic. A primary benefit of partial classes is allowing different programmers to work on different parts of the same class at the same time. They also make automatically generated code easier to interpret, as it is separated from other code into a partial class. Partial classes have been around in SmallTalk under the name of Class Extensions for considerable time. In pre-beta versions of Visual Studio 2005 the partial keyword was known as "expands" in Visual Basic. With the arrival of the .NET framework 2 Microsoft then introduced partial classes (see partial types), supported in both C# 2.0 and Visual Basic 2005.
[edit] Subclasses and superclasses
Classes are often related in some way. The most popular of these relations is inheritance, which involves subclasses and superclasses, also known respectively as child classes (or derived classes) and parent classes (or base classes). If [car] was a class, then [Jaguar] and [Porsche] might be two sub-classes. If [Button] is a subclass of [Control], then all buttons are controls. Subclasses usually consists of several kinds of modifications (customizations) to their respective superclasses: addition of new instance variables, addition of new methods and overriding of existing methods to support the new instance variables.
Conceptually, a superclass should be considered as a common part of its subclasses. This factoring of commonality is one mechanism for providing reuse. Thus, extending a superclass by modifying the existing class is also likely to narrow its applicability in various situations. In Object-oriented design, careful balance between applicability and functionality of superclasses should be considered. Subclassing is different from subtyping in that subtyping deals with common behaviour whereas subclassing is concerned with common structure.
Some programming languages (for example C++) allow multiple inheritance -- they allow a child class to have more than one parent class. This technique has been criticized by some for its unnecessary complexity and being difficult to implement efficiently, though some projects have certainly benefited from its use. Java, for example has no multiple inheritance, as its designers felt that it would add unnecessary complexity.
Sub- and superclasses are considered to exist within a hierarchy defined by the inheritance relationship. If multiple inheritance is allowed, this hierarchy is a directed acyclic graph (or DAG for short), otherwise it is a tree. The hierarchy has classes as nodes and inheritance relationships as links. The levels of this hierarchy are called layers or levels of abstraction. Classes in the same level are more likely to be associated than classes in different levels.
There are two slightly different points of view as to whether subclasses of the same class are required to be disjoint. Sometimes, subclasses of a particular class are considered to be completely disjoint. That is, every instance of a class has exactly one most-derived class, which is a subclass of every class that the instance has. This view does not allow dynamic change of object's class, as objects are assumed to be created with a fixed most-derived class. The basis for not allowing changes to object's class is that the class is a compile-time type, which does not usually change at runtime, and polymorphism is utilised for any dynamic change to the object's behaviour, so this ability is not necessary. And design that does not need to perform changes to object's type will be more robust and easy-to-use from the point of view of the users of the class.
From another point of view, subclasses are not required to be disjoint. Then there is no concept of a most-derived class, and all types in the inheritance hierarchy that are types of the instance are considered to be equally types of the instance. This view is based on a dynamic classification of objects, such that an object may change its class at runtime. Then object's class is considered to be its current structure, but changes to it are allowed. The basis for allowing object's class to change is performance. It's more efficient to allow changes to object's type, since references to the existing instances do not need to be replaced with references to new instances when the class of the object changes. However, this ability is not readily available in all programming languages. The performance analysis depends on the proposition that dynamic changes to object structure are common. This may or may not be the case in practice.
[edit] Reasons for implementing classes
Classes, when used properly, can accelerate development by reducing redundant code entry, testing and bug fixing. If a class has been thoroughly tested and is known to be a solid work, it stands to reason that implementing that class or extending it will reduce if not eliminate the possibility of bugs propagating into the code. In the case of extension new code is being added so it also requires the same level of testing before it can be considered solid.
Another reason for using classes is to simplify the relationships of interrelated data. Rather than writing code to repeatedly draw a GUI window on the terminal screen, it is simpler to represent the window as an object and tell it to draw itself as necessary. With classes, GUI items that are similar to windows (such as dialog boxes) can simply inherit most of their functionality and data structures from the window class. The programmer then need only add code to the dialog class that is unique to its operation. Indeed, GUIs are a very common and useful application of classes, and GUI programming is generally much easier with a good class framework.
[edit] Categories of classes
[edit] Abstract and concrete classes
An abstract class, or abstract base class (ABC), is one that is designed only as a parent class and from which child classes may be derived, and which is not itself suitable for instantiation. Abstract classes are often used to represent abstract concepts or entities. The incomplete features of the abstract class are then shared by a group of sibling sub-classes which add different variations of the missing pieces. In C++, an abstract class is defined as a class having at least one pure virtual method, i.e., an abstract method, which may or may not possess an implementation.
Abstract classes are superclasses which contain abstract methods and are defined such that concrete subclasses are to extend them by implementing the methods. The behaviors defined by such a class are "generic" and much of the class will be undefined and unimplemented. Before a class derived from an abstract class can be instantiated, it must implement particular methods for all the abstract methods of its parent classes.
In computing, when specifying an abstract class, the programmer is referring to a class which has elements that are meant to be implemented by inheritance. The abstraction of the class methods to be implemented by the sub-classes is meant to simplify software development.
A concrete class, however, is a class for which entities (instances) may be created. This contrasts with abstract classes which can not be instantiated because it defeats its purpose of being an 'abstract'.
Most object oriented programming languages allow the programmer to specify which classes are considered abstract and will not allow these to be instantiated (in Java, for example, the keyword abstract is used). This also enables the programmer to focus on planning and design. The actual implementation of course is to be done in the derived classes.
In C++, an abstract class is a class having at least one pure virtual function. They can not be instantiated and will generate an error if an attempt is made. They are meant to function as stubs, allowing the programmer to identify what modules of functions (behaviour or methods) are needed without having to actually implement them. This is in line with OOP's philosophy of allowing the programmer to concentrate on how an object should behave without going into the actual detail.
[edit] Metaclasses
Metaclasses are classes whose instances are classes. A metaclass describes a common structure of a collection of classes. A metaclass can implement a design pattern or describe a shorthand for particular kinds of classes. Metaclasses are often used to describe frameworks.
In some languages such as Smalltalk and Ruby, a class is also an object; thus each class is an instance of the unique metaclass, which is built in the language. For example, in Objective-C, each object and class is an instance of NSObject. CLOS (Common Lisp Object System) provides metaobject protocols (MOP) to implement those classes and metaclasses.
[edit] Non-class-based programming
To the surprise of some familiar with the use of classes in OOP, it has been shown that one can design full fledged object-oriented languages that do not have builtin support of classes. Those languages are usually designed with the motive to address the problem of tight-coupling between implementations and interfaces due to the use of classes. For example, the Self language was designed to show that the role of a class can be substituted by using an extant object which serves as a prototype to a new object, and the resulting language is as expressive as Smalltalk with more generality in creating objects. See class-based OOP for the criticism of class-based programming and object-based languages for such non-class-based languages.
[edit] Run-time representation of classes
As a datatype, a class is usually considered as a compile-time construct. A language may also support prototype or factory metaobjects that represent run-time information about classes, or even represent metadata that provides access to reflection facilities and ability to manipulate data structure formats at run-time. Many languages distinguish this kind of run-time type information about classes from a class on the basis that the information is not needed at run-time. Some dynamic languages do not make strict distinctions between run-time and compile-time constructs, and therefore may not distinguish between metaobjects and classes.
For example: if humans is a metaobject representing the class Person, then instances of class Person can be created by using the facilities of the human metaobject.
[edit] Classes without inheritance
Not every language that both supports objects and classes is generally seen as object-oriented. Examples are earlier versions of Visual Basic, which lack the support for inheritance. The lack of inheritance severely impairs the full practice of object-oriented programming. Those languages, sometimes called "object-based languages", do not provide the structural benefits of statically type checked interfaces for objects. This is because in object-based languages it is possible to use and extend data structures and attach methods to them at run-time. This precludes the compiler or interpreter from being able to check the type information specified in the source code as the type is built dynamically and not defined statically. Most of these languages allow for instance behaviour and complex operational polymorphism (see dynamic dispatch and polymorphism).
[edit] Instantiation
As explained above, classes can be used to create new objects by instantiating them. In most languages, the structures as defined by the class determine how the memory used by its instances will be laid out. This technique is known as the cookie-cutter model.
The alternative to the cookie-cutter model is that of for instance Python, where objects are structured as associative key-value containers. In such models, objects that are instances of the same class could contain different instance variables, as state can be dynamically added to the object. This may resemble Prototype-based languages in some ways, but it is not equivalent.
[edit] Examples
[edit] C++
[edit] Example 1
#include <iostream> #include <string> class Hello { std::string what; public: Hello(const char* s) : what(s) { } void say() { std::cout << "Hello " << what << "!" << std::endl; } }; int main( int argc, char** argv ) { Hello hello_world("world"); hello_world.say(); return 0; }
This example shows how to define a C++ class named "Hello". It has a private string attribute named "what", and a public method named "say".
[edit] Example 2
class Abstract { public: virtual void MyVirtualMethod() = 0; }; class Concrete : public Abstract { public: void MyVirtualMethod() { //do something } };
An object of class Abstract cannot be created because the function MyVirtualMethod has not been defined (the =0 is C++ syntax for a pure virtual function, a function that must be part of any derived concrete class but is not defined in the abstract base class. The Concrete class is a concrete class because its functions (in this case, only one function) have been declared and implemented.
[edit] Example 3
#include <string> using std::string; class InetMessage { string m_subject, m_to, m_from; public: InetMessage (const string& subject, const string& to, const string& from) : m_subject(subject), m_to(to), m_from(from) { } string subject () const { return m_subject; } string to () const { return m_to; } string from () const { return m_from; } };
[edit] Java
[edit] Example 1
public class Example1 { // This is a Java class, it automatically extends the class Object public static void main (String args[]){ System.out.println("hello everybody"); }
This example shows the simplest Java class possible.
[edit] Example 2
public class Example2 extends Example1 { // This is a class that extends the class created in Example 1. protected int data; public Example2() { // This is a constructor for the class. It does not have a return type. data = 1; } public int getData() { return data; } public void setData(int d) { data = d; } }
This example shows a class that has a defined constructor, one member data, and two accessor methods for that member data. It extends the previous example's class. Note that in Java all classes automatically extend the class Object. This allows you to write generic code to deal with objects of any type.
[edit] REALbasic
[edit] Example 1
Class Hello Private Dim what as String Sub Constructor( s as String ) what = s End Sub Sub Say() MsgBox "Hello " + what + EndOfLine End Sub End Class Sub App.Open() dim h as new Hello( "Foobar" ) h.Say End Sub
This example is a port of the C++ example above. It demonstrates how to make a class named Hello with a private property named what. It also demonstrates the proper use of a constructor, and has a public method named Say. It also demonstrates how to instantiate the class and call the Say method.
[edit] PHP
[edit] Example 1
<?php class A { public function foo() { if (isset($this)) { echo '$this is defined ('; echo get_class($this); echo ")\n"; } else { echo "\$this is not defined.\n"; } } } ?>
[edit] Example 2
<?php class date { var $date; function __construct() { $this->date = date('c'); } private function getDate() { return $this->date; } public function printDate() { echo 'Todays Date is ' . this->getDate() . '\n'; } } ?>
[edit] C#
[edit] Example 1
using System; public class Program { public static void Main(string[] args) { Console.WriteLine("Hello world!"); } }
This example demonstrates a traditional "Hello world!" example in Microsoft's C# language. The Program class contains a single static method, Main(), which calls System.Console.WriteLine to print text onto the console.
[edit] Example 2
using System; public class Hello { private string what; public Hello(string s) { what = s; } public void Say() { Console.WriteLine("Hello " + what + "!"); } } public class Program { public static void Main(string[] args) { Hello helloWorld = new Hello("world"); helloWorld.Say(); // prints "Hello world!" onto the console } }
This is another port of the above C++ example. A class called Hello is created with a constructor that takes a string parameter. When the Say() method is called, the instance of Hello will print "Hello {what}!" onto the console. Notice that the Main() method (the entry point) is actually contained in a class itself.
[edit] Actionscript
[edit] Example 1
class Cart { private var cart:Array; function Cart() { this.cart = new Array(); } public function addItem(id:Number, name:String):Void { this.cart.push([id, name]); } public function removeItemById(id:Number):Void { var ln:Number = this.cart.length; for (var i:Number = 0; i<ln; i++) { var curr:Array = this.cart[i]; if (curr[0] == id) this.cart.splice(i, 1); } } public function removeItemByName(name:String):Void { var ln:Number = this.cart.length; for (var i:Number = 0; i<ln; i++) { var curr:Array = this.cart[i]; if (curr[1] == name) this.cart.splice(i, 1); } } }
[edit] See also
- Java Classes and Objects
- Implementation inheritance
- Inheritance semantics
- Instantiation
- Hierarchy
- Class diagram (UML)
- Virtual Inheritance
- Class-based programming
[edit] Literature
- Meyer, B.: "Object-oriented software construction", 2nd edition, Prentice Hall, 1997, ISBN 0-13-629155-4
- Rumbaugh et al.: "Object-oriented modeling and design", Prentice Hall, 1991, ISBN 0-13-630054-5
- ISO/IEC 14882:2003 Programming Language C++, International standard
- Abadi; Cardelli: A Theory of Objects