Ëåêöèÿ 7. ÎÎÏ: èíêàïñóëÿöèÿ. · 2019. 11. 8. · ×åðíûé ÿùèê äëÿ...
TRANSCRIPT
Ëåêöèÿ 7. ÎÎÏ: èíêàïñóëÿöèÿ.
Åâãåíèé Ëèíñêèé
×åðíûé ÿùèê äëÿ äèíàìè÷åñêîãî ìàññèâà
int *array = new int[size];
array[i] = ...
...
delete [] array;
Çàäà÷è ïðîãðàììèñòà:
I íå çàáûòü ñîçäàòü
I íå âûéòè ñëó÷àéíî çà ãðàíèöû
I íå ïåðåïóòàòü ðàçìåð
I íå çàáûòü óäàëèòü
C++ 2 / 21
×åðíûé ÿùèê äëÿ äèíàìè÷åñêîãî ìàññèâà
array.h
class Array {
private:
size_t size;
int *data;
public:
Array(int s); // êîíñòðóêòîð
~Array (); // äåñòðóêòîð
};
array.cpp
#include "array.h"
Array :: Array(size_t s) {
size = s;
data = new int [size];
}
Array :: ~Array () {
delete [] data;
}
C++ 3 / 21
Òåðìèíîëîãèÿ
#include "array.h"
main() {
Array a(100); // âûçîâ êîíñòðóêòîðà Array(...)
// direct initialization
Array a(); // the most vexing parse??!
a.data [34] = 3434; //compilation error, data � private
} //âûçîâ äåñòðóêòîðà ~Array()
Ê private ìîæíî ïîëó÷èòü äîñòóï òîëüêî èç ìåòîäîâ òîãî æå êëàññà.Òåðìèíîëîãèÿ:
1 int a;
int � òèï ïåðåìåííîéa � èìÿ ïåðåìåííîé
2 Array a(100);
Array � êëàññ (class)a � îáúåêò/ýêçåìïëÿð êëàññà (object/instance)a.data � ïîëå (�eld)a.get_size() � ìåòîä (method)
C++ 4 / 21
Äîñòóï ê ïîëÿì
array.h
class Array {
private:
size_t size;
int *data;
public:
Array(int s);
int get(int i);
void set(int i, int v);
size_t get_size ();
~Array ();
};
C++ 5 / 21
Äîñòóï ê ïîëÿì
array.cpp
int Array ::get(int i) {
if((i < 0) || (i >= size))
return -1;
return data[i];
}
void Array ::set(int i, int val) {
if ((i < 0) || (i >= size))
return;
data[i] = val;
}
size_t Array:: get_size () {
return size;
}
1 ×òî íå òàê?
2 Îáðàáîòêà îøèáîê: get � íåëüçÿ îòëè÷èòü îøèáêó îò óñïåõà; set� îá îøèáêå íå óçíàåì â âûçûâàþùåì êîäå.
C++ 6 / 21
Äîñòóï ê ïîëÿì
array.cpp
int Array ::get(int i) {
if((i < 0) || (i >= size))
return -1;
return data[i];
}
void Array ::set(int i, int val) {
if ((i < 0) || (i >= size))
return;
data[i] = val;
}
size_t Array:: get_size () {
return size;
}
1 ×òî íå òàê?2 Îáðàáîòêà îøèáîê: get � íåëüçÿ îòëè÷èòü îøèáêó îò óñïåõà; set
� îá îøèáêå íå óçíàåì â âûçûâàþùåì êîäå.
C++ 6 / 21
Ñ style èíêàïñóëÿöèÿ
Ñ style
struct array_s {
size_t size;
int *data;
};
typedef array_t struct array_s;
void init(array_t *a, size_t s) {
a->size = s;
a->data = malloc(s * sizeof(int ));
}
void deinit(array_t *a) {
free(a->data);
}
int main() {
array_t a;
init(&a, 100);
deinit (&a);
}
C++ 7 / 21
Ðåàëèçàöèÿ èíêàïñóëÿöèè
Ïîñëå êîìïèëÿöèè (â îáúåêòíîì ôàéëå) îò êëàññà íè÷åãî�èíêàïñóëÿöèîííîãî� íå îñòàåòñÿ. Ìîæíî ñ÷èòàòü ÷òî êîìïèëÿòîðïðåîáðàçóåò ïðîãðàììó òàê:
struct Array {
size_t size;
int *data;
};
void Array :: Array(Array *this , size_t s) {
this ->size = s;
this ->data = new int [s];
}
void Array ::~ Array(Array *this) {
delete [] this ->data;
}
int main() {
Array a;
//ïðîñòî âûçîâ îáû÷íîé ôóíöèè ñ òàêèì ñòðàííûì èìåíåì
Array:: Array(&a, 100);
Array ::~ Array (&a);
}
C++ 8 / 21
Ðåàëèçàöèÿ èíêàïñóëÿöèè
class Array {
private:
...
};
//void Array::set(Array *this, int i, int val) ...
void Array ::set(int i, int val) { this ->data[i] = val; }
int main() {
Array a(100);
a.set(3, 10);
Array b(100);
b.set(5, 20)
}
I Âñå ïðîâåðêè private/public âûïîëíÿþòñÿ òîëüêî âî âðåìÿêîìïèëÿöèè (â äâîè÷íîì êîäå óæå íè÷åãî ïðèâàòíîãî íåò)
I Íóëåâîé ïàðàìåòð this âñåì ôóíêöèÿì äîáàâëÿåò äëÿ íàñêîìïèëÿòîð (this ìîæíî èñïîëüçîâàòü)
I Â ïðîãðàììå âûøå â ïàìÿòè áóäåò õðàíèòñÿ 2 íàáîðàïåðåìåííûõ (a è b) è 1 êîä ôóíêöèè set
C++ 9 / 21
Ïåðåãðóçêà (overloading) â C++
 C++ ìîæíî òàê:
int max(int a, int b) { ... }
int max(int a, int b, int c) { ... }
I Name mangling (ìàíãëèíã) � �ïðåîáðàçîâàíèå èìåíè ôóíêöèèêîìïèëÿòîðîì äëÿ ëèíêåðà�
I â C:
max(int a, int b) �> maxmax(int a, int b, int c) �> max
I â C++ (êàê-òî òàê):
max(int a, int b) �> max_int_intmax(int a, int b, int c) �> max_int_int_int
I Òî åñòü ìîæíî, íàïðèìåð, ñäåëàòü äâà êîíñòðóêòîðà
C++ 10 / 21
Êîíñòðóêòîð ïî óìîë÷àíèþ (default constructor)
class Array {
...
Array(int s) { size = s; data = new int [size]; }
Array() { size = 100; data = new int [size]; }
};
int main() {
Array a; // âûçîâ default êîíñòðóêòîðà
Array b(100);
}
Åñëè ó êëàññà íåò êîíñòðóêòîðà èëè äåñòðóêòîðà, òî êîìïèëÿòîðñãåíåðèðóåò òàêèå:
Array() { }
~Array() { }
C++ 11 / 21
Êîíñòðóêòîð êîïèé (copy constructor)
int main() {
int a = 3;
int b = a;
}
Õî÷ó ïîëüçîâàòüñÿ îáúåêòàìè êàê îáû÷íûìè ïåðåìåííûìè.
1 int main() {
2 Array a(200);
3 a.set(3, 42);
4 Array b(a); // õî÷ó, ÷òîáû b áûë êîïèåé a
5 b.set(3, 24);
6 }
Ïî óìîë÷àíèþ ó îáúåêòîâ (êàê è ó ñòðóêòóð) ïðîèçîéäåò ïîáàéòîâîåêîïèðîâàíèå ïîëåé.
1 Íó è ÷òî?
2 Ïîëÿ data ó a è ó b áóäóò óêàçàûâàòü íà îäíî è òî æå ìåñòî âïàìÿòè (b.set(...) ïîìåíÿåò a).
3 Â ñòðîêå 6 ïðîèçîéäåò äâîéíîé âûçîâ delete íà îäèí è òîò æåàäðåñ �> ïðîãðàììà óïàäåò.
C++ 12 / 21
Êîíñòðóêòîð êîïèé (copy constructor)
int main() {
int a = 3;
int b = a;
}
Õî÷ó ïîëüçîâàòüñÿ îáúåêòàìè êàê îáû÷íûìè ïåðåìåííûìè.
1 int main() {
2 Array a(200);
3 a.set(3, 42);
4 Array b(a); // õî÷ó, ÷òîáû b áûë êîïèåé a
5 b.set(3, 24);
6 }
Ïî óìîë÷àíèþ ó îáúåêòîâ (êàê è ó ñòðóêòóð) ïðîèçîéäåò ïîáàéòîâîåêîïèðîâàíèå ïîëåé.
1 Íó è ÷òî?2 Ïîëÿ data ó a è ó b áóäóò óêàçàûâàòü íà îäíî è òî æå ìåñòî â
ïàìÿòè (b.set(...) ïîìåíÿåò a).
3 Â ñòðîêå 6 ïðîèçîéäåò äâîéíîé âûçîâ delete íà îäèí è òîò æåàäðåñ �> ïðîãðàììà óïàäåò.
C++ 12 / 21
Êîíñòðóêòîð êîïèé (copy constructor)
int main() {
int a = 3;
int b = a;
}
Õî÷ó ïîëüçîâàòüñÿ îáúåêòàìè êàê îáû÷íûìè ïåðåìåííûìè.
1 int main() {
2 Array a(200);
3 a.set(3, 42);
4 Array b(a); // õî÷ó, ÷òîáû b áûë êîïèåé a
5 b.set(3, 24);
6 }
Ïî óìîë÷àíèþ ó îáúåêòîâ (êàê è ó ñòðóêòóð) ïðîèçîéäåò ïîáàéòîâîåêîïèðîâàíèå ïîëåé.
1 Íó è ÷òî?2 Ïîëÿ data ó a è ó b áóäóò óêàçàûâàòü íà îäíî è òî æå ìåñòî â
ïàìÿòè (b.set(...) ïîìåíÿåò a).3 Â ñòðîêå 6 ïðîèçîéäåò äâîéíîé âûçîâ delete íà îäèí è òîò æå
àäðåñ �> ïðîãðàììà óïàäåò.C++ 12 / 21
Êîíñòðóêòîð êîïèé (copy constructor)
class Array {
...
Array(const Array& a) {
size = a.size;
data = new int [size];
for(size_t i = 0; i < size; i++) data[i] = a.data[i];
}
};
Åùå êîíñòðóêòîð êîïèé íóæåí ïðè ïåðåäà÷å îáúåêòà ïî çíà÷åíèþ âôóíêöèþ:
void create_copy_and_fill_it(Array a) {
...
}
1 À ïî÷åìó Array(const Array& a), à íå Array(Array a)?
2 Áóäåò áåñêîíå÷íàÿ ðåêóðñèÿ.
C++ 13 / 21
Êîíñòðóêòîð êîïèé (copy constructor)
class Array {
...
Array(const Array& a) {
size = a.size;
data = new int [size];
for(size_t i = 0; i < size; i++) data[i] = a.data[i];
}
};
Åùå êîíñòðóêòîð êîïèé íóæåí ïðè ïåðåäà÷å îáúåêòà ïî çíà÷åíèþ âôóíêöèþ:
void create_copy_and_fill_it(Array a) {
...
}
1 À ïî÷åìó Array(const Array& a), à íå Array(Array a)?
2 Áóäåò áåñêîíå÷íàÿ ðåêóðñèÿ.
C++ 13 / 21
Êîíñòðóêòîð êîïèé (copy constructor)
void print(Array a) {
for(size_t i = 0; i < a.get_size (); i++ ){
print("%d ", a.get(i));
}
}
1 Õîðîøàÿ èäåÿ?
2 Íåò. Ëèøíèå íàêëàäíûå ðàñõîäû íà âûçîâ êîíñòðóêòîðà êîïèé.Ëó÷øå ïåðåäàòü ïî êîíñòàíòíîé ññûëêå print(const Array& a).
C++ 14 / 21
Êîíñòðóêòîð êîïèé (copy constructor)
void print(Array a) {
for(size_t i = 0; i < a.get_size (); i++ ){
print("%d ", a.get(i));
}
}
1 Õîðîøàÿ èäåÿ?
2 Íåò. Ëèøíèå íàêëàäíûå ðàñõîäû íà âûçîâ êîíñòðóêòîðà êîïèé.Ëó÷øå ïåðåäàòü ïî êîíñòàíòíîé ññûëêå print(const Array& a).
C++ 14 / 21
Îïåðàòîð ïðèñâàèâàíèÿ (copy assignment)
int main() {
int a = 3;
int b = 5;
b = a;
}
Õî÷ó ïîëüçîâàòüñÿ îáúåêòàìè êàê îáû÷íûìè ïåðåìåííûìè.
int main() {
Array a(200); a.set(3, 42);
Array b(20); b.set(3, 24);
b = a;
}
Ïî óìîë÷àíèþ ó îáúåêòîâ (êàê è ó ñòðóêòóð) ïðîèçîéäåò ïîáàéòîâîåêîïèðîâàíèå ïîëåé.
1 Áóäóò àíàëîãè÷íûå ïðîáëåìû, êàê è ó êîíñòðóêòîðà êîïèé.2  ÷åì ðàçíèöà îò ïðåäûäóùåãî ñëó÷àÿ?
3 Ñëó÷àé 1: îáúåêòà b íå áûëî è åãî íàäî ñîçäàòü êàê êîïèþ a.Ñëó÷àé 2: îáúåêò b óæå ñóùåñòâóåò, åãî íàäî �îáíóëèòü� è ïîòîìñîçäàòü êàê êîïèþ a.
C++ 15 / 21
Îïåðàòîð ïðèñâàèâàíèÿ (copy assignment)
int main() {
int a = 3;
int b = 5;
b = a;
}
Õî÷ó ïîëüçîâàòüñÿ îáúåêòàìè êàê îáû÷íûìè ïåðåìåííûìè.
int main() {
Array a(200); a.set(3, 42);
Array b(20); b.set(3, 24);
b = a;
}
Ïî óìîë÷àíèþ ó îáúåêòîâ (êàê è ó ñòðóêòóð) ïðîèçîéäåò ïîáàéòîâîåêîïèðîâàíèå ïîëåé.
1 Áóäóò àíàëîãè÷íûå ïðîáëåìû, êàê è ó êîíñòðóêòîðà êîïèé.2  ÷åì ðàçíèöà îò ïðåäûäóùåãî ñëó÷àÿ?3 Ñëó÷àé 1: îáúåêòà b íå áûëî è åãî íàäî ñîçäàòü êàê êîïèþ a.
Ñëó÷àé 2: îáúåêò b óæå ñóùåñòâóåò, åãî íàäî �îáíóëèòü� è ïîòîìñîçäàòü êàê êîïèþ a.
C++ 15 / 21
Îïåðàòîð ïðèñâàèâàíèÿ (copy assignment).
Âåðñèÿ 1.
void Array :: operator =(const Array& a) {
delete [] data;
size = a.size;
data = new int [size];
for(int i = 0; i < size; i++) data[i] = a.data[i];
}
C++ 16 / 21
Îïåðàòîð ïðèñâàèâàíèÿ (copy assignment).
Âåðñèÿ 2.
1 Array& Array :: operator =( const Array &a){
2 if (&a == this){
3 return *this;
4 }
5 delete [] data;
6 size = a.size;
7 data = new int [size];
8 for (int i = 0; i < size; i++){
9 data[i] = a.data[i];
10 }
11 return *this;
12}
1 Çà÷åì ñòðîêè 2-4 è 11?
2 2-4: a = a;
3 11: a = b = c;
C++ 17 / 21
Îïåðàòîð ïðèñâàèâàíèÿ (copy assignment).
Âåðñèÿ 2.
1 Array& Array :: operator =( const Array &a){
2 if (&a == this){
3 return *this;
4 }
5 delete [] data;
6 size = a.size;
7 data = new int [size];
8 for (int i = 0; i < size; i++){
9 data[i] = a.data[i];
10 }
11 return *this;
12}
1 Çà÷åì ñòðîêè 2-4 è 11?
2 2-4: a = a;
3 11: a = b = c;
C++ 17 / 21
Îïåðàòîð ïðèñâàèâàíèÿ (copy assignment).
Âåðñèÿ 2.
1 Array& Array :: operator =( const Array &a){
2 if (&a == this){
3 return *this;
4 }
5 delete [] data;
6 size = a.size;
7 data = new int [size];
8 for (int i = 0; i < size; i++){
9 data[i] = a.data[i];
10 }
11 return *this;
12}
1 Çà÷åì ñòðîêè 2-4 è 11?
2 2-4: a = a;
3 11: a = b = c;
C++ 17 / 21
Êîïèðóþùàÿ èíèöèàëèçàöèÿ (copy initialization)
= íå âñåãäà îçíà÷àåò ¾îïåðàòîð ïðèñâàèâàíèÿ¿:
int main() {
Array a;
// ...
Array b = a; // Âñåãäà âûçûâàåòñÿ Array(const Array&).
print(b); // Îáû÷íî âûçûâàåòñÿ Array(const Array&) äëÿ
// ñîçäàíèÿ àðãóìåíòà.
}
Array print(Array a) {
// ...
return a; // Copy init âîçâðàùàåìîãî çíà÷åíèÿ.
// Array(const Array&).
}
Ñìîòðèì íà êîíñòðóêòîðû ñ îäíèì ïàðàìåòðîì.
C++ 18 / 21
Íåÿâíûå ïðåîáðàçîâàíèÿ (implicit conversion)
Êîïèðóþùàÿ èíèöèàëèçàöèÿ âûãëÿäèò êàê ïðåîáðàçîâàíèå òèïîâ:
int main() {
Array a(10); // Array(10) ≈ Array(int).
Array b = 10; // Array(10) ≈ Array(int).
print (10); // Âûçûâàåòñÿ Array(int), ÷òîáû ñîçäàòü àðãóìåíò.
}
void print(Array a) { ... }
// void print(int i) { ... } // Ïåðåãðóçêà äîáàâèò âåñåëüÿ.
Array singleCellArray () {
return 10; // Array(10) ≈ Array(int).
}
C++ 19 / 21
Explicit-êîíñòðóêòîð (C++11)
 C++11 ìîæíî îòêëþ÷èòü êîíñòðóêòîð äëÿ êîïèðóþùåéèíèöèàëèçàöèè:
class Array {
...
explicit Array(int n) { ... }
...
};
int main() {
Array a(10); // Êîìïèëèðóåòñÿ.
Array b = 10; // Íå êîìïèëèðóåòñÿ.
print (10); // Íå êîìïèëèðóåòñÿ.
}
C++ 20 / 21
RVO, NRVO, copy elision
Array createArray () {
// Ñîçäà¼òñÿ âðåìåííûé îáúåêò, à ïîòîì êîïèðóåòñÿ?
// Return value optimization (îáÿçàòåëüíî ñ C++17).
return Array (10);
}
Array createArray () {
Array a(10); // Ñîçäà¼òñÿ ëîêàëüíàÿ ïåðåìåííàÿ.
// Ïåðåìåííàÿ êîïèðóåòñÿ â âîçâðàùàåìîå çíà÷åíèå è
// óíè÷òîæàåòñÿ?
// Íåîáÿçàòåëüíûé named return value optimization.
return a;
}
Êîìïèëÿòîð ìîæåò âûêèíóòü âûçîâ, äàæå åñëè â êîïèðóþùåìêîíñòðóêòîðå ïðîèñõîäèò ÷òî-òî, êðîìå êîïèðîâàíèÿ:
Array(const Array &a) { printf("copy!\n"); ... }
Ìîæíî âûêèíóòü íå òîëüêî ðÿäîì ñ return:
print(Array (10)); // Ìîæíî ñîçäàòü ñðàçó íà ìåñòå ïàðàìåòðà.
C++ 21 / 21