zestaw3

Transkrypt

zestaw3
Imię i nazwisko: przykładowe odpowiedzi
Numer:
EGZAMIN II • Język C++ • 5 września 2013
1. Co to jest hermetyzacja danych i w jaki sposób jest realizowana podczas pisania klasy?
Hermetyzacja czyli ukrywanie wszelkich składowych klasy, zwłaszcza danych. Polega na
umieszczaniu ich w części prywatnej klasy, względnie w części chronionej. Hermetyzacja jest
częścią abstrakcji (czyli procesu tworzenia typów złożonych) i elementem dobrego
projektowania obiektowego.
2. Mamy klasę bazową, z której potem będzie dziedziczone:
class Foo {
public:
virtual void fun() = 0;
virtual ~Foo() = 0;
};
Co jeszcze należy dopisać, żeby (z technicznego punktu widzenia) mogła być użyta jako klasa
bazowa do typów potomnych i gdzie to należy dopisać?
Konieczna jest definicja destruktora, nie może on pozostać czysto wirtualny. Można to zrobić
poza ciałem klasy, np. Foo::~Foo() { }
3. Proszę zakreślić wszystkie błędy w poniższym fragmencie kodu:
class Foo { public:
// dwuarg. operator+ zwraca tymczasowy obiekt, nie można uczynić tego przez referencję
Foo& operator+(Foo const &);
// operator<< ma zwracać referencję do strumienia, czyli ostream&
friend Foo& operator<<( ostream& );
// destruktor nie może mieć żadnego argumentu, nawet domyślnego
virtual ~Foo( const int a = 0 );
};
4. Proszę napisać fragment kodu z dowolną pętlą, dzięki któremu policzona zostanie suma liczb
od 1 do 1000 (tzn. 1 + 2 + … + 1000):
// można to napisać na wiele sposobów
int suma = 0;
for (auto i(0); i<1000; ++i) suma += i+1;
5. Wskaż wszystkie poprawne odpowiedzi:
a. • w std::vector efektywnie dodaje się elementy na końcu
b. • std::list nie można obsługiwać jak tablicy, bo nie ma operatora[]
c. std::array jest tablicą, do utworzenia której wystarczy podać typ parametru
d. std::deque jest kontenerem skojarzeniowym
str. 1
6. Czym należy zainicjalizować poniższą zmienną, żeby uzyskać stały iterator do kontenera v,
wskazujący na jego początek (patrz kod):
std::vector< int > v;
auto it = v.cbegin() ;
7. Jakiego typu (napisać kompletnie) jest zmienna a:
auto a = { 1, 2, 3, 4, 5 };
a jest typu initializer_list<int>
8. Co się stanie w wyniku kompilacji poniższego fragmentu kodu:
int const* ptr;
ptr = new int[3];
ptr[2] = 3; // błąd kompilacji, ptr jest wskaźnikiem na stały int i nie można zniemiać
9. Mamy klasę bazową:
class Foo { public:
Foo(int, int);
Foo(double);
};
Napisz klasę potomną publicznie dziedziczącą (o nazwie Bar, może być pusta) i zapisz w jaki
sposób można odziedziczyć konstruktory (C++11):
class Bar : public Foo {
public:
using Foo::Foo; // oba konstruktory się dziedziczy
};
10.
11.
Proszę napisać deklarację globalnych operatorów preinkrementacji i postinkrementacji dla
jakiegoś typu Foo:
const Foo& operator++(Foo& a); // preinkrementacja (operator przedrostkowy)
const Foo operator++(Foo&, int); // postinkrementacja (operator przyrostkowy)
// const w typie zwracanym zalecane, ale niekonieczne
Niech klasy Foo i Bar są niezależnymi od siebie typami. Co się stanie w dwóch poniższych
przypadkach rzutowania:
Bar p1;
Foo *p2 = dynamic_cast< Foo* >( &p1 );
// p2 ustawione na 0 (a dokładnie na std::nullptr)
Foo &p3 = dynamic_cast< Foo& >( p1 );
// zgłoszenie wyjątku (typu std::bad_cast)
12. Funkcja zwraca referencję do typu T, co zatem napiszemy w instrukcji powrotu wewnątrz
funkcji (np. zwracamy a):
T& fun ( T& a ) {
return a;
}
str. 2
13. Napisz przykład rzutowania (w stylu C++) z typu T const * na typ T * const
T const * ptr1 = … // jakaś inicjalizacja
T * const ptr2 = const_cast< T * const >( ptr1 );
14. Jakiego typu będzie zwykle obiekt obsługujący czytanie strumienia plikowego:
std::ifstream (również std::fstream ale z odpowiednią opcją konstruktora)
15. Proszę zaznaczyć (zakreślić kółkiem) wszystkie błędy w poniższym kodzie:
// funkcja globalna nie może mieć kwalifikatora cv
int fun() const ;
// typ zwracany przez main() to int
auto main() -> void { }
struct Foo { static Foo p; }; // tu nie ma błędu
16. Napisz fragment kodu klasy Foo, w której zablokujesz (w stylu C++11) operacje kopiowania
(rzecz jasna, należy przy tej okazji napisać poprawnie deklaracje konstrkutora kopiującego
i operatora przypisania kopiującego):
Foo ( const Foo& ) = delete;
Foo& operator= (const Foo& ) = delete;
17. Mamy typ Foo, w którym są różne konstruktory, np. Foo(int); Foo(int,int);
Foo(int,int,int); Napisz jak zainicjalizować 3-elementową dynamicznie tworzoną
(operator new) tablicę Foo tak, żeby każde z jej pól było inicjalizowane innym
konstruktorem (jak wyżej):
Foo *ptr = new Foo[3] { Foo(1), Foo(1,2), Foo(1,2,3) };
18. Dlaczego taki zapis konstruktora przenoszącego (jest możliwy, ale) nie ma sensu?
Foo( const Foo && );
Ponieważ const blokuje operację przenoszenia („zabierania zawartości”), a przecież taki
jest właśnie cel konstruktora przenoszącego. Możliwe jest wtedy tylko kopiowanie.
19. Napisz wyrażenie Lambda takie, że wszystkie zewnętrzne zmienne przyjmuje przez
referencję, za wyjątkiem w, które przyjmuje przez wartość, następnie ma argument
wywołania int m oraz do zmiennej suma dodaje iloczyn w * m
int suma;
int w;
[ &, w ] ( int m ) { suma += w * m; };
20. Mamy tablicę int tab[] = { 1, 2, 3 };
Napisz pętlę for po całym zakresie (C++11) taką, żeby zawartość tablicy była podniesiona
do kwadratu:
for ( auto& i : tab ) i = i*i;
str. 3
21. Mamy trzy przeładowane funkcje:
void fun( char* ); // 1
void fun( int ); // 2
void fun( double ); // 3
Która z nich zostanie wywołana, jeśli napiszemy:
fun( NULL );
Zostanie wywołane fun(int) ponieważ NULL jest konwertowane na 0 (to był jeden z
powodów wprowadzenia w C++11 typu std::nullptr, określającego zerowe wskaźniki)
22. Gdzie można definiować przestrzenie nazw (namespaces) – wymień dwie możliwe lokacje:
1) w przestrzeni globalnej
2) zagnieżdżone w innej przestrzeni nazw
23. Klasa Foo jest zdefiniowana przez użytkownika. Napisz, co oznacza poniższy zapis:
Foo matrix();
Jest to deklaracja bezargumentowej funkcji matrix, zwracającej (przez wartość) typ Foo.
24. Napisz (jakś przykład) definicję silnego typu wyliczeniowego zbudowanego na typie char:
enum class Kolor : char { czerwony, zielony, niebieski };
25. Który z niżej wymienionych typów wbudowanych nie istnieje w C++11
a. long long
b. short
c. unsigned long long int
d. true // to jest wartość typu bool
e. double double // poprawnie by było long double
26. Klasa bazowa to:
class Foo {
double f;
protected:
double f();
public:
double f() const;
};
Co się stanie, jeśli w klasie potomnej Bar, dziedziczącej prywatnie z Foo, w jej części
publicznej napiszemy using Foo::f;
Prawidłowa odpowiedź: klasa Foo nie może się skompilować, ponieważ deklaracja double f;
wchodzi w konflikt z kolejną deklaracją double f();
Gdyby w części prywatnej Foo była zamiast zmiennej jakaś przeciążona metoda o nazwie f,
wtedy otrzymalibyśmy podczas kompilowania Bar błąd niedostępności tej składowej.
str. 4
27. W klasie Foo jest metoda składowa:
const char* fun( double, int& ) const;
Proszę napisać wskaźnik do takiej metody składowej i zainicjalizować go nią:
typedef const char* (Foo::*FP)( double, int& ) const;
// zamiast typedef można też
// using FP = const char* (Foo::*)( double, int& ) const;
FP funptr = &Foo::fun;
// można by bez typedef utworzyć wskaźnik, ale potem byłby on przypisany,
// a nie zainicjalizowany, więc ściśle rzecz biorąc, utworzenie typu FP jest konieczne
// jeśli chce się zrobić taki wskaźnik i go zainicjalizować
28. Co (jaka wartość) wyświetli się na ekranie po wykonaniu takiego kodu:
int i = 0;
cout << ((++(++i))++) << endl;
Wartość 2 (efekt dwóch preinkrementacji).
29. Mamy wskaźnik do funkcji, np.: double (*fp) (double);
Proszę za pomocą składni using utworzyć nową zamienną nazwę do takiego typu (coś, co
przed C++11 wykonywało się tylko za pomocą typedef):
using FP = double (*) (double);
30. Mamy kontener std::list<int> d; wypełniony jakimiś wartościami i chcemy go
posortować w odwrotnej kolejności niż domyślne kryterium („mniejszy niż”). Zapisz
wywołanie odpowiedniej metody sort z takim argumentem – funktorem, żeby sortowanie
było według warunku „większy niż”
d.sort( greater<int>() );
31. Co dokładnie dzieje się, jeśli podczas alokowania pamięci operatorem new zabraknie
pamięci na stercie?
W sytuacji krytycznej wywoływana jest funkcja obsługi wskazywana przez wskaźnik
(new_handler), który można (za pomocą set_new_handler) ustawić na swoją
funkcję. Domyślnie zgłaszany jest następnie wyjątek std::bad_alloc.
32. Wskaż wszystkie linie, w których będzie błąd:
// Zapis z nawiasami { } zapobiega konkwersji, np. zaokrąglaniu
a. int d { 3.14 }; // błąd kompilacji, nie można zaokrąglić
b. int d = { 3.14 }; // jak wyżej
c. char d { 9 }; // ok (trywialna konwersja z int na char)
d. std::deque<unsigned> d { 1, 2.1, 3, 4.2 }; // błąd j.w.
str. 5
33. Mamy klasę:
class Foo {
int a = 3;
double d = 3.14;
public:
Foo() : d(a*a) { a(0); }
};
Jaką wartość będzie miała składowa a oraz d po utworzeniu obiektu tej klasy?
Składowa a ma wartość 0, składowa d wartość 9, taką jak podczas inicjalizacji (wtedy
a miało jeszcze wartość 3, zatem wyliczone a*a daje wartość 9).
34. Mamy klasę Bar. Napisz deklarację oraz definicję składowej statycznej typu Foo:
class Bar {
static Foo var; // deklaracja
};
Foo Bar::var; // definicja
35. Napisz deklarację funkcji bezargumentowej, która zwraca zbiór trzech wartości typu:
int, double, string (należy w tym celu skorzystać z n-tupli z C++11):
std::tuple< int, double, std::string > fun();
str. 6

Podobne dokumenty