• Nie Znaleziono Wyników

Programming and Data Structures Programming and Data Structures

N/A
N/A
Protected

Academic year: 2021

Share "Programming and Data Structures Programming and Data Structures"

Copied!
13
0
0

Pełen tekst

(1)

Programming and Data Structures Programming and Data Structures

Lecture 2 Lecture 2

Dr Piotr Cybula <piotr.cybula@wmii.uni.lodz.pl>

Dr Piotr Cybula <piotr.cybula@wmii.uni.lodz.pl>

(2)

Encapsulation : data protection Encapsulation : data protection

code safety and independence

better team support with the code separation

without «giving a monkey a razor» (black-box solution)

different levels of data access in a class (through access specifiers):

public – available for everyone

private – available only for the member functions of that class (methods)

protected – like private, but additionally available for the inherited classes

friend – available for implicitly pointed non-member functions or other classes

constant methods guaranteeing no changes of an object they are called for

(3)

Data protection : struct Data protection : struct

Within the struct statement all members are public by default:

struct Student

{ private: //hidden members string name;

int index;

bool checkIndex(int _index); //internal method public: //public interface

Student(string _name);

Student();

~Student();

int getIndex() const; //getter

void setIndex(int _index); //setter … //inne metody

};

Student s(”Scott Tiger”);

s.setIndex(12345); //public method call s.checkIndex(); //compile-time error

(4)

Data protection : class Data protection : class

Within the class statement all members are private by default:

class Student

{ //hidden members, private keyword optional string name;

int index;

bool checkIndex(int _index); //internal method public: //public interface

Student(string _name);

Student();

~Student();

int getIndex() const; //getter

void setIndex(int _index); //setter … //inne metody

};

Student s(”Scott Tiger”);

s.setIndex(12345); //public method call s.checkIndex(); //compile-time error

(5)

Invariants Invariants

rules (logical sentences) describing the consistent state of a structure/class (correct attribute values)

private auxiliary methods that check these rules

each public method (including constructors) assumes that the object for which it was called is in a consistent state and guarantees that it will remain in such a state after its completion (design based on a contract – design by contract)

the public method changing the state of an object (modifier) is to check the compliance of such a change with the rules described by invariants

if the rules are exceeded, the method is obliged to report an exceptional situation (throw exception)

the exception thrown in the constructor prevents the object from being

created (no destructor is called)

(6)

Invariants Invariants

#include <stdexcept>

class Student { string name;

int index;

float avg;

//class invariants:

//index is a positive number //avg is between 2.0 and 5.0 public: //interfejs publiczny Student(string _name);

void setIndex(int _index) //modyfikator

{ if(_index <= 0) throw invalid_argument(”Error”);//exception index = _index;

}};

Student s1(”Scott Tiger”), s2(”John Smith”);

try {

s1.setIndex(12345); //ok

s2.setIndex(-1234); //exception throw

} catch(exception &e) { cout << e.what(); } //exception catch

(7)

Overloading of operators Overloading of operators

redefinition of the built-in operator functions for a class objects as operands

name of the function consists of the keyword operator followed by the operator name or symbol, i.e. operator+, operator=, etc.

overloaded operators can be methods or friend functions (some of them must be methods)

there is no possibility to create any new operator, and to change the priority of the evaluation of the operators

it's «syntactic sugar» – do not overload any operator, when it is not necessary

for the improvement of the code readability

(8)

Unary operators Unary operators

without arguments

it should be a constant method

class Vector { double x, y;

public:

Vector(double _x = 0, double _y = 0) { x = _x; y = _y; } Vector operator-() const

{ return Vector(-x, -y);

}};

Vector v1(2, -3);

Vector v2(-v1); //unary operator call v2 = -v1; //also here

v2 = v1.operator-(); //alternative call

(9)

Binary operators Binary operators

with only one argument if overloaded as a class method (member function)

class Vector { double x, y;

public:

Vector(double _x = 0, double _y = 0) { x = _x; y = _y; } Vector operator+(const Vector &v) const

{ return Vector(x + v.x, y + v.y);

}};

Vector v1(2, -3), v2(-1, 4), v3;

v3 = v1 + v2; v3 = v1 + 2; //binary operator calls v3 = v1.operator+(v2); //alternative call

(10)

Binary operators Binary operators

with two arguments if overloaded as a friend function with constant

arguments to enable the automatic conversions of the both operands from simpler types

class Vector { double x, y;

public:

Vector(double _x = 0, double _y = 0) { x = _x; y = _y; }

friend Vector operator+(const Vector &v1, const Vector &v2);

};

Vector operator+(const Vector &v1, const Vector &v2) { return Vector(v1.x + v2.x, v1.y + v2.y);

}Vector v1(2, -3), v2(-1, 4), v3;

v3 = v1 + v2; v3 = v1 + 2; //binary operator calls v3 = 2 + v1; //binary operator call

v3 = v1.operator+(v2); //compile-time error v3 = operator+(v1, v2); //alternative call

(11)

Indexing oparator [ ] Indexing oparator [ ]

must be as a class method (member function) with single argument

should return a reference for use on the left-hand side of the assigment operator

class Vector { double x, y;

public:

Vector(double _x = 0, double _y = 0) { x = _x; y = _y; } double& operator[](int i)

{ return (i == 1) ? x : y;

}};

Vector v1(2, -3), v2(-1, 4);

double d = v1[1] + v2[2]; //indexing operator calls

v1[1] = 5; //also here (thanks to the reference returned)

(12)

Shift operators << and >>

Shift operators << and >>

overloaded typically for input/output streams

the left operand is of the other type (ostream or istream), so the operator must be a friend function and it should pass and return references to the stream (for the cascade call possibility)

class Vector { double x, y;

public:

Vector(double _x = 0, double _y = 0) { x = _x; y = _y; }

friend ostream& operator<<(ostream &stream, const Vector &v);

friend istream& operator>>(istream &stream, Vector &v);

};ostream& operator<<(ostream &stream, const Vector &v) { stream << '[' << v.x << ',' << v.y << ']';

return stream;

}Vector v1(2, -3), v2(-1, 4) ;

cout << v1 << ' ' << v2 << endl; //shift operator cascade calls

(13)

Assignment operator = Assignment operator =

must be a class method (member function) with single argument being a reference to an existing object of the same type and it should return a reference for cascade usage

automatically created if (and only if) no explicitly defined but copying the fields by simple bit-copy (risky when there are some pointer fields), so always

overload the assignment operator for classes with pointer fields

class Vector { double x, y;

public:

Vector(double _x = 0, double _y = 0) { x = _x; y = _y; } Vector& operator=(const Vector &v)

{ if (this != &v) { x = v.x; y = v.y; } return *this;

}};

Vector v1(2, -3), v2, v3;

Cytaty

Powiązane dokumenty

● destructor, copy constructor and assignment operator (as for bounded) insertion/removal

(3) set a dedicated pointer (killer) to the last node using the address in the next pointer of the node pointed to by tmp (or the head pointer if tmp is empty, or the tail pointer

● during instantiation of a template with a specific type, the compiler replaces each instance of a parametric type with the specified type and compiles the data structure

(1) set the pred pointer on the node preceding the deleted node, and succ on the node to be removed (if there is no node we are looking for, throw an exception or abort the

(1) create two auxiliary pointers: set pred to an empty address, and succ on to the address of the first node (head) and pass the auxiliary pointers towards the end of the list

(1) by comparing values, go from root to children and set the pred pointer on the parent node to be removed, and succ on the node to be removed (if there is no node we are looking

(1) invoke two auxiliary pointers set on the adjacent nodes pred and succ (assume that the pointers next in the preceding nodes pointed to by succ are already inverted, succ is

● input/output streams: iostream, fstream, sstream, iomanip. ● string