Cóż - ostatnia zagadka była nieco trudna - przyznaję. Po raz kolejny mogę pogratulować poprawnego rozwiązania
beluosusowi. Postaram się pokrótce wyjaśnić, o co w niej chodziło.
Mieliśmy zdefiniowaną funkcję void f(), która przyjmowała nieokreśloną liczbę argumentów. Tak naprawdę znaliśmy tylko pierwszy argument, który to oznaczał, ile dodatkowych argumentów owa funkcja będzie przyjmować. Następnie wczytywaliśmy dodatkowe argumenty za pomocą funkcji z nagłówka
cstdarg.
W językach C oraz C++ przekazujemy argumenty w następujący sposób:
f(a,b,c)
Gdzie a,b,c są oczywiście argumentami. Nie każdy się jednak zastanawiał,
jak to działa
od środka.
Załóżmy, że mamy następujący program:
- int f(int a, int b) {
- return 123;
- }
-
- int main() {
- int a=2, b=3;
- f(a,b);
- return 0;
- }
int f(int a, int b) {
return 123;
}
int main() {
int a=2, b=3;
f(a,b);
return 0;
}
Jeżeli każemy naszemu kompilatorowi wygenerować kod asemblerowy naszego programu (w przypadku GCC musimy użyć atrybutu -S), to po dużym uproszczeniu będziemy mogli zobaczyć coś takiego.
- movl $2, -12(%ebp)
- movl $3, -8(%ebp)
- pushl -8(%ebp)
- pushl -12(%ebp)
- call f
movl $2, -12(%ebp)
movl $3, -8(%ebp)
pushl -8(%ebp)
pushl -12(%ebp)
call f
Oznacza to mniej więcej, że
kopiujemy wartość 2 do rejestru o adresie -12(%ebp) (nasza zmienna a), oraz wartość 3 do rejestru o adresie -8(%ebp). Następnie wrzucamy oba te rejestry na stos (czyt. - dodajemy je do listy argumentów) po czym wywołujemy instrukcję
call f, która wywołuję funkcję int f() w oparciu o argumenty pobrane ze stosu. Należy pamiętać, że argumenty wrzucamy na stos
w odwrotnej kolejności.
Ot cała filozofia.
Wymyślanie zagadek nie należy do najłatwiejszych zajęć, tak więc skorzystam z zasłyszanego kiedyś gotowca. Zagadka dająca odpocząć troszeczkę od programowania niskopoziomowego.
W języku Java istnieje słowo kluczowe
final, które w zależnie od kontekstu ma różne znaczenia. W tej zagadce zajmiemy się użyciem tego słowa w stosunku do
klas. W Javie klasą finalną nazywamy klasę, z której
nie możemy dziedziczyć.
I na tym będzie polegać Wasze zadanie. Zaprojektujcie klasę Klasa, dla której nie będzie możliwe utworzenie obiektu klasy pochodnej.
- class Klasa {
-
- public:
- void f() {
- cout << "Czesc, jestem klasa finalna!\n";
- }
- };
-
- class Dziecko : public Klasa {
- };
-
- int main() {
- Dziecko obj;
- return 0;
- }
class Klasa {
// TUTAJ MODYFIKACJA
public:
void f() { // publiczna funkcja skladowa, user musi miec mozliwosc wykonania jej w swoim programie
cout << "Czesc, jestem klasa finalna!\n";
}
};
class Dziecko : public Klasa {
};
int main() {
Dziecko obj; // NIEDOZWOLONE!
return 0;
}
Miłej zabawy.