IMIĘ i NAZWISKO: przykładowe odpowiedzi NR: 0 EGZAMIN 2 (14 WRZEŚNIA 2015) JĘZYK C++ 1. Napisz precyzyjnie co to jest ptr jeśli: const * const Foo ptr; ptr to stały wskaźnik do stałego obiektu typu Foo 2. Proszę zdefiniować w oparciu o typ std::array 5-elementową tablicę o nazwie tab, typu size_t, oraz zainicjalizować ją dowolnym zestawem wartości. array< size_t, 5 > tab { 0 // można oczywiście zainicjalizować dowolnie, { 1, 2, 3, 4, 5 itp. 3. Na czym polega błąd w poniższym kodzie? int main( ) { auto fun( ) -> int { return 1; Oprócz literówki nawias [ miał być { to nie wolno zagnieżdżać definicji funkcji w innej funkcji. 4. Jaki jest typ zwracany przez funkcję fun: auto fun(int i) { if (i==1) return i; else return fun(i-1) + i; // Typ zwracany to int wydedukowany z pierwszej instrukcji return 5. Czy dwie poniższe funkcje mogą istnieć w wersji przeciążonej - uzasadnij. void fun(int tab1[10]); void fun(int tab2[5]); Nie mogą bo ich argumenty są nierozróżnialne (najbardziej lewy indeks wielkości tablicy nie ma znaczenia więc typ jest w obu przypadkach analogiczny do int*). 6. Proszę napisać pętlę z użyciem składni "range based loop" (po całym zakresie) w taki sposób, że do tablicy tab wstawiona zostanie podwojona wartość: int tab[ ] { 1,2,3,4 for ( auto& i : tab ) i = 2*i; // można też for( int&... 7. Po prawej stronie jest jakościowy opis wielkości przypisywanej (lewa prawa stała modyfikowalna wartość). Które linie są błędne? const int&& cpr1 = modyfikowalna_lwartosc; // błąd const int&& cpr2 = stala_lwartosc; // błąd const int&& cpr3 = modyfikowalna_pwartosc( ); // OK const int&& cpr4 = stala_pwartosc( ); // OK 8. Napisz wewnątrz klasy Foo operator rzutowania na typ const char* (używając zmiennej string s;) Pamiętaj, żeby operator był metodą stałą. class Foo { string s; public: operator const char*( ) const { return s.c_str( ); 1
9. Dla klasy Foo (jeszcze raz: dla klasy Foo czyli typu Foo) proszę napisać deklarację globalnego operatora inkrementacji w wersji "pre" i "post" (sama deklaracja wystarczy). const Foo& operator++( Foo& obj ); // przedrostkowy const Foo operator++( Foo& obj, int ); // przyrostkowy // const na początku jest opcjonalne 10. Mamy funkcję - co w niej jest niepoprawnego? int& fun( int k ) { //... return k; Nie wolno zwracać referencji do lokalnej zmiennej, ponieważ argument jest przekazywany przez wartość, więc k to lokalna kopia (i lokalna zmienna o czasie życia ograniczonym do funkcji). 11. Oto fragment kodu: class Foo { int a{3, b{4 Foo( int m, int n ) : a(m), b(n) { public: Foo( ) : Foo( 1, 2 ) { int geta( ) const { return a; int getb( ) const { return b; int main( ) { cout << Foo( ).geta( ) << " " << Foo( ).getb( ) << endl; Czy i jakie wartości zobaczymy na ekranie? Zobaczymy 1 2 nadane przez konstruktor domyślny. Obiekty są tworzone dwa razy w locie. 12. Co zobaczymy w przypadku wykonania tego kodu: cout << ( 1^2^3 ) << endl; 0 ponieważ ^ to XOR czyli 01 ^ 10 daje 11 (czyli decymalnie 3) a dalej 3^3 daje 0 13. Przyjrzyj się uważnie i napisz ile razy na ekranie zobaczymy "ctora" a ile razy "dtora": class A { public: A( ) { cout<<"ctora"<<endl; ~A( ) { cout<<"dtora"<<endl; static A a; int main( ) { A *ptr = new A; A b = a; 2 razy ctora i 2 razy dtora. Po jednym dla statycznego obiektu a, następnie jeden ctora dla obiektu tworzonego operatorem new (ale ten obiekt nie jest usuwany!), zaś jeden dtora dla obiektu b (ten z kolei toworzny jest konstruktorem kopiującym automatycznie wygenerowanym). 2
14. Dla klasy: class Foo { public: int a, b, c; zdefiniuj wskaźnik na składową int oraz ustaw go od razu na jedną ze składowych w klasie Foo. int Foo::*ptr = &Foo::a; 15. Napisz wskaźnik na metodę składową klasy o nazwie Foo taką, że przyjmuje argument typu string& i nic nie zwraca. void ( Foo::*fp ) ( string& ); 16. Obok operatorów napisz ile mają argumentów ich wersje przeciążone przez użytkownika: a) operator= // 2 b) operator-> // 1 c) operator->* // 2 d) operator( ) // dowolną od 0 wzwyż 17. Dla klasy Foo napisz operator<< dzięki któremu jego składowe a i b wysłane będą do strumienia (jak w przykładzie poniżej). class Foo { int a, b; friend ostream& operator<<( ostream& s, const Foo& obj ); ostream& operator<<( ostream& s, const Foo& obj ) { return s << obj.a << " " << obj.b; 18. Jaki jest typ pierwszego argumentu każdej wersji operatora new? size_t (całkowity bezznakowy), formalnie wyliczany jest na potrzeby operatora za pomocą sizeof 19. Napisz jak poprawnie skasować te obiekty, które należy na koniec usunąć: int main() { int *p1 = new auto(0); int *p2 = new int[2]; static int p3 = 0; delete p1; delete [ ] p2; 20. W jakiej części klasy potomnej Bar będzie składowa int a; klasy Foo wg poniższego kodu: class Foo { protected: int a; class Bar : private Foo { public: using Foo::a; W części publicznej (de facto zostanie "promowana" z protected do public). 21. Podaj kolejność wywołania konstruktorów podczas tworzenia obiektu C c; class A { class B : public A { MY my; MX mx; class C : public B { MW mw; MZ mz; A MY MX B MW MZ C 3
22. Zaznacz obok, co jest dziedziczone: a) destruktory b) składowe statyczne // dziedziczone c) operator= d) operator rzutowania // dziedziczone (precyzyjniej, operator konwersji) 23. Co się stanie w przypadku poniższego kodu (nieistotne szczegóły pominięto): class Foo { public: explicit Foo(int); // w programie: Foo f1 = { 3 Z powodu "explicit" niemożliwe jest niejawne wywołanie konstruktora, zatem błąd kompilacji. 24. Ktory z konstruktorów zostanie wywołany? class Foo { public: Foo( int a, int b ); // 1 Foo( std::initializer_list<int> a ); // 2 // w kodzie Foo f1(1,2); 1 (ze względu na użyte nawiasy) 25. Napisz dowolne wyrażenie lambda przyjmujące argument typu int, a następnie napisz przykład jak je "zachować" i wywołać tak jakby to była funkcja. auto semifun = [ ]( int a ) { /* cokolwiek */ semifun(7); 26. W jaki sposób przekazywane są do wnętrza wyrażenia lambda zmienne a,b,c jeśli na początku wyrażenia lambda widzimy zapis: [ =, &c ] a i b przez wartość (kopię), c przez referencję 27. Napisz abstrakcyjną klasę Foo bazową do Bar (minimum konieczne) tak, żeby wywołanie metody foo było polimorficzne. class Foo { public: virtual void fun( ) = 0; class Bar : public Foo { void fun( ) { // w programie Foo *ptr = new Bar; prt->fun( ); 28. Co oznacza RTTI i napisz jakiś przykład jak się tego używa. Run Time Type Identification określenie typu podczas wykonywania programu Dodając nagłówek #include <typeinfo> można użyć typeid np. int k; typeid( int ) == typeid( k ); 4
29. Co oznacza wirtualne dziedziczenie i kiedy budowane są 'klasy' tak dziedziczone. Jest to dziedziczenie dzięki któremu powstaje w całym kodzie jeden egzemplarz danej klasy (wirtualnie dziedziczonej) dzięki czemu unika się kłopotów kolizji w wielokrotnym dziedziczeniu. Taka klasa jest budowana na samym początku i za dostarczenie właściwych argumentów do konstruktora takiej klasy odpowiada obiekt najbardziej potomny. 30. Jaki iterator obsługuje kontenery vector i deque? Iterator swobodnego dostępu (tzw. random access iterator). 31. Mamy listę list<int> m; wypełnioną jakimiś wartościami. Napisz prostą strukturę będącą obiektem funkcyjnym sortującym elementy tej listy, a potem użyj go do posortowania. struct MySort { bool operator( )( const int& lewy, const int& prawy ) { return lewy < prawy; // w kodzie m.sort( MySort( ) ); 32. Mamy std::tuple< A, B, C > obiekt(1,2,3); oraz B b; Za pomocą std::tie proszę "wydobyć" z obiekt wartość składowej b (i tylko niej). std::tie( std::ignore, b, std::ignore ) = obiekt; 33. Jakiego typu będzie m jeśli: using tt = map<int,string>; tt k; decltype((k)) m = k; m jest typu map<int,string>& (referencja do mapy int i string, musi być zainicjalizowana). 34. Mamy obiekt Foo f; Jak należy zapisać wywołanie metody void fun( Foo&& ); z argumentem f, żeby rzeczywiście nastąpiło przeniesienie zawartości obiektu f? Trzeba "opakować" (zasłonić tożsamość) f które jest lewą wartością: fun ( std::move( f ) ); 35. Napisz dowolny przykład definicji silnego typu wyliczeniowego opartego na zmiennej typu short enum class Typ : short { pan, pani // można też użyć słowa kluczowego struct 5