niedziela, 29 sierpnia 2010

Dziedziczenie prywatne w C++

Dziedziczenie prywatne nie jest zbyt często wykorzystywane w programowaniu, jednakże jest ono możliwe, pewnie z chęci podrzymania niejako 'kompletności' języka. Dzisiejsza zagadka będzie dotyczyła właśnie tego mechanizmu.

Mamy następujący kod:

class Bazowa {
        public:
                int a;
};
class Dziecko : private Bazowa {
                // MODYFIKACJA
};
int main() {
        Dziecko a;
        a.a=5;
        cout << a.a << "\n";
        return 0;
}

Polega ona na podaniu przynajmniej dwóch takich modyfikacji wskazanego miejsca, aby kod skompilował się i działał.

Miłej zabawy.

czwartek, 19 sierpnia 2010

Przekazywania wartości do funkcji ciąg dalszy oraz klasa finalna w C++

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;
}

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

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 {
 // 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.

sobota, 14 sierpnia 2010

Przekazywanie argumentów do funkcji

Cześć,
W poprzedniej zagadce mogliście się wykazać sporą kreatywnością w uzupełnianiu nudnej luki pomiędzy int a main(). Jak się okazało, wcale nie była taka trudna, bo niemal każdy wymyślił swoje własne rozwiązanie. Gratuluję, jestem pełen podziwu.

Następna zagadka będzie dotyczyć przekazywania argumentów do funkcji. Do rozwiązania jej w sposób, który mam na myśli potrzebna jest dosyć szczegółowa wiedza z tego zakresu. Pozwolę sobie wkleić następujący kod:
#include <iostream>
#include <cstdarg>
using namespace std;
int f(int z, ...) {
        int val;
        va_list vl;
        va_start(vl,z);
        val = va_arg(vl,int);
        return val;
}

int main() {
        // TYLKO W TYM MIEJSCU MOŻESZ WPROWADZIĆ MODYFIKACJĘ
        cout << f(1) << "\n";
        return 0;
}

Zadanie polega na tym, aby modyfikując kod programu w miejscu które wskazałem sprawić, że funkcja f(1) zwróci 8.
Od razu zaznaczam, że rozwiązanie polegające na nadpisaniu globalnej funkcji f() lokalną nie wchodzi w grę.

Miłej zabawy.

czwartek, 12 sierpnia 2010

int... main( )?

Trochę mnie nie było, ale wynagrodzę to Wam dosyć ambitną zagadką. Jest najkrótsza z dotychczasowych, ale chyba najtrudniejsza.

co można wstawić za X:

int X main() {
 return 0;
}
X jest dowolnym, skończonym ciągiem niebiałych (w sensie - nie tylko białych) znaków. Podaj przynajmniej dwie możliwości.

Have fun. :^)

wtorek, 10 sierpnia 2010

Pascal w C

Ostatnia zagadka została poprawnie rozwiązana przez dwie osoby. Pierwsze działające rozwiązanie nadesłał Adam (podpisujący się w komentarzach jako Rekin). Później, krótsze rozwiązanie zaproponował Railis. Gratulacje.


Dzisiaj zagadka bardziej ze znajomości C, niż C++. Kompilator C++ jednak też powinien akceptować rozwiązanie. Zagadka jest stara jak świat a jej treść brzmi następująco:

Spraw, aby poniższy kod został skompilowany przez kompilatory C/C++:

begin
        writeln("Hello world");
end;

I wyprodukował napis: Hello World, po czym zakończył swoją pracę. Oczywiście bez modyfikacji tychże linijek.
Tradycyjnie już: miłej zabawy.

PS: Wiem, że "pascalowość" tegoż kodu jest troszeczkę naciągana. ;)

poniedziałek, 9 sierpnia 2010

P nie jest równe NP

Wygląda na to, że został rozwiązany jeden z największych (jeżeli nie największy!) problem w historii Informatyki. Zdaje się, że pan Vinay Deolalikar z Hewlett-Packard udowodnił, że P nie jest równe NP.

Link znaleziony na wykopie:

http://gregbaker.ca/blog/2010/08/07/p-n-np/

Sam dowód znajduje się tutaj http://www.scribd.com/doc/35539144/pnp12pt i jest obszerny na całe 100 stron. Trzeba przyznać, że wygląda poważnie.
No cóż, wygląda na to, że stworzenie szybkiego (działającego w czasie wielomianowym) algorytmu na znalezienie cyklu Hamiltona jest niemożliwe. Chyba, że ktoś znajdzie błąd w dowodzie.

Zagadka - zmiana wartości składnika stałego obiektu bez użycia modyfikatora.

Poprzednia zagadka została rozwiązana przez beluosusa, któremu chciałbym z tego miejsca pogratulować.

Przykładowa metoda zmieniająca wartość tegoż składnika:
void TClass::change(int i) const {
        TClass *wsk = const_cast<TClass*>(this);
        wsk->a = i;
}

Ten sam człowiek jest pomysłodawcą zmodyfikowanej (czytaj: trudniejszej) wersji zagadki. Oto jej treść:

Mamy klasę TClass, posiadającą prywatny składnik 'int a', oraz metodę get(), zwracającą wartość tegoż składnika. Utwórz stały obiekt tej klasy, a następnie zmień wartość składnika a BEZ UŻYCIA MODYFIKATORA. Całość powinna pasować do następującego wzorca:

class TClass {
    int a;
public:
    TClass(int i = 0) {
        a = i;
    }
    int get() const {
        return a;
    }
};

int main() {
    const TClass obj;
    cout << obj.get() << "\n"; // niech wypisze 0.
        // W TYM MIEJSCU WPROWADŹ SWOJĄ MODYFIKACJĘ.
    cout << obj.get() << "\n"; // niech wypisze 5.
    return 0;
}

Miłej zabawy. ;-)