Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CPlusPlusNotesForProfessionals.pdf
Скачиваний:
47
Добавлен:
20.05.2023
Размер:
5.11 Mб
Скачать

Chapter 34: Classes/Structures

Section 34.1: Class basics

A class is a user-defined type. A class is introduced with the class, struct or union keyword. In colloquial usage, the term "class" usually refers only to non-union classes.

A class is a collection of class members, which can be:

member variables (also called "fields"),

member functions (also called "methods"),

member types or typedefs (e.g. "nested classes"),

member templates (of any kind: variable, function, class or alias template)

The class and struct keywords, called class keys, are largely interchangeable, except that the default access specifier for members and bases is "private" for a class declared with the class key and "public" for a class declared with the struct or union key (cf. Access modifiers).

For example, the following code snippets are identical:

struct Vector

{

int x; int y; int z;

};

// are equivalent to class Vector

{

public: int x; int y; int z;

};

By declaring a class` a new type is added to your program, and it is possible to instantiate objects of that class by

Vector my_vector;

Members of a class are accessed using dot-syntax.

my_vector.x =

10;

my_vector.y

=

my_vector.x + 1; // my_vector.y = 11;

my_vector.z

=

my_vector.y - 4; // my:vector.z = 7;

 

 

 

Section 34.2: Final classes and structs

Version ≥ C++11

Deriving a class may be forbidden with final specifier. Let's declare a final class:

class A final { };

Now any attempt to subclass it will cause a compilation error:

 

GoalKicker.com – C++ Notes for Professionals

170

// Compilation error: cannot derive from final class: class B : public A {

};

Final class may appear anywhere in class hierarchy:

class A { };

// OK.

class B final : public A { };

// Compilation error: cannot derive from final class B. class C : public B {

};

Section 34.3: Access specifiers

There are three keywords that act as access specifiers. These limit the access to class members following the specifier, until another specifier changes the access level again:

Keyword

Description

public Everyone has access

protected Only the class itself, derived classes and friends have access

private Only the class itself and friends have access

When the type is defined using the class keyword, the default access specifier is private, but if the type is defined using the struct keyword, the default access specifier is public:

struct MyStruct { int x; }; class MyClass { int x; };

MyStruct s;

s.x = 9; // well formed, because x is public

MyClass c;

c.x = 9; // ill-formed, because x is private

Access specifiers are mostly used to limit access to internal fields and methods, and force the programmer to use a specific interface, for example to force use of getters and setters instead of referencing a variable directly:

class MyClass {

public: /* Methods: */

int x() const noexcept { return m_x; }

void setX(int const x) noexcept { m_x = x; }

private: /* Fields: */

int m_x;

};

Using protected is useful for allowing certain functionality of the type to be only accessible to the derived classes, for example, in the following code, the method calculateValue() is only accessible to classes deriving from the

GoalKicker.com – C++ Notes for Professionals

171

base class Plus2Base, such as FortyTwo:

struct Plus2Base {

int value() noexcept { return calculateValue() + 2; } protected: /* Methods: */

virtual int calculateValue() noexcept = 0;

};

struct FortyTwo: Plus2Base { protected: /* Methods: */

int calculateValue() noexcept final override { return 40; }

};

Note that the friend keyword can be used to add access exceptions to functions or types for accessing protected and private members.

The public, protected, and private keywords can also be used to grant or limit access to base class subobjects. See the Inheritance example.

Section 34.4: Inheritance

Classes/structs can have inheritance relations.

If a class/struct B inherits from a class/struct A, this means that B has as a parent A. We say that B is a derived class/struct from A, and A is the base class/struct.

struct A

{

public: int p1;

protected: int p2;

private: int p3;

};

//Make B inherit publicly (default) from A struct B : A

{

};

There are 3 forms of inheritance for a class/struct:

public

private

protected

Note that the default inheritance is the same as the default visibility of members: public if you use the struct keyword, and private for the class keyword.

It's even possible to have a class derive from a struct (or vice versa). In this case, the default inheritance is controlled by the child, so a struct that derives from a class will default to public inheritance, and a class that derives from a struct will have private inheritance by default.

public inheritance:

struct B : public A // or just `struct B : A`

{

GoalKicker.com – C++ Notes for Professionals

172

void foo()

{

p1 = 0; //well formed, p1 is public in B

p2 = 0; //well formed, p2 is protected in B p3 = 0; //ill formed, p3 is private in A

}

};

B b;

b.p1 = 1; //well formed, p1 is public b.p2 = 1; //ill formed, p2 is protected b.p3 = 1; //ill formed, p3 is inaccessible

private inheritance:

struct B : private A

{

void foo()

{

p1 = 0; //well formed, p1 is private in B p2 = 0; //well formed, p2 is private in B p3 = 0; //ill formed, p3 is private in A

}

};

B b;

b.p1 = 1; //ill formed, p1 is private b.p2 = 1; //ill formed, p2 is private b.p3 = 1; //ill formed, p3 is inaccessible

protected inheritance:

struct B : protected A

{

void foo()

{

p1 = 0; //well formed, p1 is protected in B p2 = 0; //well formed, p2 is protected in B p3 = 0; //ill formed, p3 is private in A

}

};

B b;

b.p1 = 1; //ill formed, p1 is protected b.p2 = 1; //ill formed, p2 is protected b.p3 = 1; //ill formed, p3 is inaccessible

Note that although protected inheritance is allowed, the actual use of it is rare. One instance of how protected

inheritance is used in application is in partial base class specialization (usually referred to as "controlled polymorphism").

When OOP was relatively new, (public) inheritance was frequently said to model an "IS-A" relationship. That is, public inheritance is correct only if an instance of the derived class is also an instance of the base class.

This was later refined into the Liskov Substitution Principle: public inheritance should only be used when/if an instance of the derived class can be substituted for an instance of the base class under any possible circumstance (and still make sense).

Private inheritance is typically said to embody a completely di erent relationship: "is implemented in terms of"

GoalKicker.com – C++ Notes for Professionals

173