Jacek Czekaj,
Data ostatniej modyfikacji: 30.IX.2009.
Instytut Matematyki,
Uniwersytet Śląski
Laboratorium programowania w C++
0. Literatura
[1] Brian W. Kernighan, Dennis M. Ritchie, Język ANSI C, Wydawnictwa Naukowo-Techniczne.
[2] Bjarne Stroustrup, Język C++, Wydawnictwa Naukowo-Techniczne.
1. Podstawy powtórka z C
Zadanie 1.1. Opisać działanie poniższego programu.
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int i;
cout << "Wpisz 0 lub 1: ";
cin
>> i;
switch (i) {
case
0: cout << "Wpisano liczbe 0.";
case
1: cout << "Wpisano liczbe 1.\n";
default: cout << "Wpisano liczbe rozna od 0 i 1.\n";
}
return 0;
}
Zadanie 1.2. Opisać działanie poniższego programu.
#include <iostream>
#include <cstring>
using namespace std;
int main(int argc, char** argv) {
union rekord {
char kategoriaWojskowa;
char nazwiskoPanienskie[256];
} r;
r.kategoriaWojskowa = ’E’;
strcpy(r.nazwiskoPanienskie, "Nowak");
cout << r.nazwiskoPanienskie << endl << r.kategoriaWojskowa;
return 0;
}
Zadanie 1.3. Opisać działanie poniższego programu.
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
1
const int i = 123;
const int * p;
cout << i << endl;
p = &i;
*p = 997;
cout << i << endl;
return 0;
}
Zadanie 1.4.
Wykorzystując wskaźniki, wypisać wartości wszystkich bajtów, które składają się na wewnętrzną
reprezentację liczby typu int. Wykonać to samo zadanie wykorzystując unie.
Przykładowe rozwiązanie:
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int n;
cout << "Podaj jakas liczbe calkowita: ";
cin
>> n;
union {
int n;
unsigned char c[sizeof(int)];
} u;
u.n = n;
for(int i = 0; i < sizeof(int); i ++)
cout << u.c[i] << ", ";
cout << endl;
unsigned char *c = (unsigned char *) &n;
for(i = 0; i < sizeof(int); i++)
cout << *(c+i) << ", ";
return 0;
}
Zadanie 1.5. Przeanalizować działanie poniższego programu.
#include <iostream>
#define MAX_X 10
#define MAX_Y 15
using namespace std;
int main(int argc, char ** argv) {
int ** tab = new int * [MAX_Y];
tab[0] =
new int [MAX_X * MAX_X];
for (int y = 1; y < MAX_Y; y ++)
tab[y] = tab[y-1] + MAX_X;
for (int y = 0; y < MAX_Y; y ++)
for (int x = 0; x < MAX_X; x ++)
tab[y][x] = x*y;
for (int y = 0; y < MAX_Y; y ++) {
for (int x = 0; x < MAX_X; x ++)
2
cout << tab[y][x] << ", ";
cout << endl;
}
delete [] tab[0];
delete [] tab;
return 0;
}
Zadanie 1.6. Napisz program, który zapyta użytkownika o imię i nazwisko, po czym napisze „Witam Panią!”, albo
„Witam Pana!”, w zależności od płci użytkownika.
Zadanie 1.7. Napisz program, który zapyta użytkownika o jedgo numer PESEL i numer albumu, po czym napisze
„Witam Panią!”, albo „Witam Pana!”, w zależności od płci użytkownika.
Zadanie 1.8. Napisać program obliczający medianę z podanych liczb.
Zadanie 1.9. Napisać program, który obliczy i wypisze iloczyn macierzy o wartościach i wymiarach wprowadzonych
przez użytkownika.
2. Strumienie wejścia/wyjścia
Zadanie 2.1. Przeanalizować działanie poniższego programu.
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char **argv)
{
//TEST STRUMIENI WYJSCIOWYCH
cout << "standardowy strumien wyjsciowy znakow\n";
cerr << "standardowy niebuforowany strumien wyjsciowy komunikatow o bledach\n";
clog << "standardowy strumien wyjsciowy komunikatow o bledach\n";
wcout << "szeroki strumien odpowiadajacy cout\n";
wcerr << "szeroki strumien odpowiadajacy cerr\n";
wcerr << "szeroki strumien odpowiadajacy clog\n";
//wypisywanie liczb calkowitych
cout << "\n" << 123
<< ", " << showpos << 123;
cout.unsetf(ios_base::showpoint|ios_base::showpos);
cout << ", " << 123
<< ", " << showpos << 123;
cout.unsetf(ios_base::showpoint|ios_base::showpos);
cout << "\n" << oct << 64
<< ", " << showbase << 64 << endl;
cout << "\n" << hex << 64
<< ", " << showbase << 64
<< ", " << uppercase << 64 << endl;
cout.unsetf(ios_base::hex|ios_base::showbase|ios_base::uppercase);
//wypisywanie wartosci boole-owkich
cout <<
"true = " << true << ", false = " << false << endl;
cout << boolalpha << "true = " << true << ", false = " << false << endl;
cout <<
"true = " << true << ", false = " << false << endl;
3
//wypisywanie liczb zmiennopozycyjnych
cout << "\nformat domyslny: " << 1234.56789; //zostanie zaokraglone, a nie obciete!!!
cout.setf(ios_base::scientific,ios_base::floatfield); //maksymalnie 2 argumenty
cout << "\nformat naukowy: " << 1234.56789;
cout.setf(ios_base::scientific,ios_base::floatfield);
cout << "\njszcze raz format naukowy: " << uppercase << 1234.56789;
cout.setf(ios_base::fixed,ios_base::floatfield);
cout << "\nformat staly: " << 1234.56789;
cout.setf(ios_base::floatfield);
cout << "\nznowu format domyslny: " << 1234.56789;
cout.precision(8);
cout << "\nzmiana domyslnej precyzji (bylo 6): " << 1234.56789 << ", " << 1234.56789;
cout.precision(4);
cout << "\nkolejna zmiana: " << 1234.56789 << ", " << 1234.56789;
//pola wyjsciowe
cout << "\n";
cout.width(4);
cout << "ab";
cout.width(4);
cout << "\n";
cout << "ab"; //teraz nie bedzie spacji wiodacych!!!
cout.width(4);
cout.fill(’0’);
cout << endl << "ab";
cout.width(4);
cout.fill(’0’);
cout << endl << 12 << ’,’ << 13; //nie wypisze 0012000,0013 tylko 0012:13 !!!
cout.fill(’0’);
cout.width(6);
cout.setf(ios_base::left,ios_base::adjustfield);
cout << endl << -12;
cout.width(6);
cout.setf(ios_base::right,ios_base::adjustfield);
cout << endl << -12;
cout.width(6);
cout.setf(ios_base::internal,ios_base::adjustfield);
cout << endl << -12;
//wypisywanie wskaznikow
int i;
int *p = new int;
cout << "\nlokalnie: " << &i << ", pamiec wolna: " << p;
//TEST STRUMIENI WEJSCIOWYCH
char s[4];
cout << "\nPROSZE NA TERMINALU WPISAC NAPIS MAJACY WIECEJ NIZ TRZY ZNAKI\n";
cin
>> s; //standardowy strumien wejsciowy znakow
cout << s << endl;
cout << "\nPROSZE ZNOWU NA TERMINALU WPISAC NAPIS MAJACY WIECEJ NIZ TRZY ZNAKI\n";
cin.width(4); //nastepne cin wczyta co najwyzej trzy znaki i doda na koniec ’\0’
cin
>> s;
cout << s << endl;
cout << "\nPROSZE JESZCZE RAZ NA TERMINALU WPISAC NAPIS MAJACY WIECEJ NIZ TRZY ZNAKI\n";
cin.get(s, 4, ’\0’);
cout << s << endl;
4
//TEST STRUMIENI PLIKOWYCH
ifstream fin ( "streams_test.cpp", ios_base::binary);
ofstream fout("˜streams_test.cpp", ios_base::binary);
unsigned char c;
fin >> noskipws;
while (!fin.eof()) {
fin
>> c;
fout << c;
}
fin.close();
fout.close();
//NA KONIEC COS, NA CO TRZEBA UWAZAC!!!
int x = 0;
cout << x << ++x << ++x << std::endl; // 221 zamiast 012
return 0;
}
Zadanie 2.2. Napisać program rysujący „choinkę” o zadanej przez użytkownika wysokości. Np. choinka o wysokości
4 powinna wyglądać następująco:
*
*
***
*
***
*****
*
***
*****
*******
Przykładowe rozwiązanie:
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
int liczbaSegmentow;
cout << "Podaj liczbe ,,segmentow’’ choinki: ";
cin
>> liczbaSegmentow;
for (int segment = 1; segment <= liczbaSegmentow; segment ++)
{
for (int liniaSegmentu = 1; liniaSegmentu <= segment; liniaSegmentu ++)
{
for (int spacja = 1; spacja <= liczbaSegmentow-liniaSegmentu; spacja ++)
cout << ’ ’;
for (int gwiazdka = 1; gwiazdka <= 2*liniaSegmentu-1; gwiazdka ++)
cout << ’*’;
cout << endl;
}
}
return 0;
}
Zadanie 2.3. Napisać program wypełniający „po spirali” tablicę kwadratową o zadanej wielkości boku.
Przykładowe rozwiązanie:
#include <iostream>
using namespace std;
int main(int argc, char** argv) {
5
int i, n, x = 0, y = 0, dir = 0, tab[100][100];
cout << "Podaj rozmiar tablicy (max 100): ";
cin
>> n;
for (i = 1; i <= n*n; i ++) {
if (x+y==n-1 || (x==y && x>=n/2) || (x+1==y && x<n/2))
dir = (dir+1) % 4;
tab[y][x] = i;
x += dir==0?1:(dir==2?-1:0);
y += dir==1?1:(dir==3?-1:0);
}
for (y = 0; y < n; y ++) {
for (x = 0; x < n; x ++) {
cout.width(4);
cout << tab[y][x];
}
cout << endl;
}
return 0;
}
Zadanie 2.4. Wykorzystując strumieine plikowe, napisać program, który będzie przyjmował dwa argumenty ozna-
czające odpowiednio nazwę pliku wejściowego oraz nazwę pliku wyjściowego, a następnie z podanego pliku wejściowego
usunie wszystkie komentarze w stylu języka C++, a wynik zapisze do podanego pliku wyjściowego.
Przykładowe rozwiązanie:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
int main(int argc, char** argv) {
ifstream
fin(argv[1], ios_base::binary);
ofstream fout(argv[2], ios_base::binary);
unsigned char c, o = 0;
int state = 0;
fin >> noskipws;
while (!fin.eof()) {
fin >> c;
if (state == 0)
state = 1;
else if (state == 1 && o == ’/’ && c == ’/’)
state = 2;
else if (state == 1 && o == ’/’ && c == ’*’)
state = 3;
else if (state == 1)
fout << o;
else if (state == 2 && c == ’\n’)
{ state = 0; fout << c; }
else if (state == 3 && o == ’*’ && c == ’/’)
state = 0;
o = c;
}
fin.close();
fout.close();
return 0;
}
3. Biblioteka standardowa STL
Zadanie 3.1. Przeanalizować działanie poniższego programu.
6
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
class inicjal {
public:
inicjal(
char cc): c(cc) { }
bool
operator()(const string &s) const { return (s[0] == c); }
private:
const char c;
};
class nieInicjal {
public:
nieInicjal(
char cc): c(cc) { }
bool
operator()(const string &s) const { return (s[0] != c); }
private:
const char c;
};
inline bool specialStringsCompare(const string &s, const string &t) {
string::
const_iterator is = s.begin();
string::
const_iterator it = t.begin();
while (is != s.end() && it != t.end() && toupper(*is) == toupper(*it)) {
is ++;
it ++;
}
if (is == s.end())
return it != t.end();
if (it == t.end())
return false;
return toupper(*is) < toupper(*it);
}
class printElement {
public:
printElement(ostream& out) : os(out) {}
void operator() (const string &s) const { os << s << endl; }
ostream& os;
};
void printElement2(const string &s) {
cout << s << endl;
}
struct pairOfDoubles {
double x, y;
pairOfDoubles(
double xx = 0, double yy = 0) : x(xx), y(yy) {}
};
int main(int argc, char** argv) {
char s1[] = "Wektor zainicjowany przy konstrukcji napisem w stylu C...";
char s2[] = "Wektor zainicjowany _po_ konstrukcji napisem w stylu C...";
int
i;
vector<
char> vc1(s1, s1 + sizeof(s1) - 1); //vector<char> vc1(s1, &s1[sizeof(s1) - 1]);
vector<
char> vc2;
7
vc2.assign(s2, s2 +
sizeof(s2) - 1);
cout << "\nwektor vc1 (dostep poprzez przeciazony operator []):\n";
for (i = 0; i < vc1.size(); i ++)
cout << vc1[i];
cout << endl;
vector<
char>::iterator ivc;
cout << "\nwektor vc2 (dostep poprzez iterator):\n";
for (ivc = vc2.begin(); ivc != vc2.end(); ivc ++)
cout << *ivc;
cout << endl;
vector<string> vs;
vs.push_back("kiwi");
vs.push_back("Mango");
vs.push_back("mango");
vs.push_back("gruszka");
vs.push_back("awokado");
vs.push_back("morela");
vs.push_back("zurawina");
cout << "\nwektor vs (dostep poprzez przeciazony operator []):\n";
for (i = 0; i < vs.size(); i ++)
cout << vs[i] << endl;
sort(vs.begin(), vs.end());
cout << "\nwektor vs (wynik po sortowaniu):\n";
for (i = 0; i < vs.size(); i ++)
cout << vs[i] << endl;
sort(vs.begin(), vs.end(), specialStringsCompare);
cout << "\nvektor vs (wynik po specjalnym sortowaniu):\n";
for (i = 0; i < vs.size(); i ++)
cout << vs[i] << endl;
sort(vs.begin(), vs.end());
vector<string>::iterator ivs1 = find_
if(vs.begin(), vs.end(), inicjal(’m’));
vector<string>::iterator ivs2 = find_
if(ivs1
, vs.end(), nieInicjal(’m’));
vs.erase(ivs1, ivs2);
cout << "\nwektor vs (wynik po usunieciu owocow na ’m’):\n";
for (i = 0; i < vs.size(); i ++)
cout << vs[i] << endl;
list<string> l1, l2;
l1.push_back ("kiwi");
l1.push_back ("Mango");
l1.push_back ("mango");
l1.push_front("gruszka");
l1.push_front("gruszka");
l2.push_front("mango");
l2.push_front("gruszka");
l2.push_back ("awokado");
l2.push_back ("morela");
l2.push_back ("zurawina");
8
list<string>::iterator ils;
cout << "\nlista l1 (dostep poprzez iterator):\n";
for (ils = l1.begin(); ils != l1.end(); ils ++)
cout << *ils << endl;
cout << "\nna liscie l1 sa " << count(l1.begin(), l1.end(), "gruszka")
<< " wpisy \"gruszka\"\n";
if (find(l1.begin(), l1.end(), "kiwi") != l1.end())
cout << "\nna liscie l1 jest element \"kiwi\"\n";
else
cout << "\nna liscie l1 nie ma elementu \"kiwi\"\n";
cout << "czy na liscie l1 jest element \"kiwi\"? " << boolalpha
<< binary_search(l1.begin(), l1.end(), "kiwi") << noboolalpha << endl;
//to bedzie duzo szybsze, dla (sporej) listy posortowanej...
cout << "\nlista l2 (dostep poprzez iterator):\n";
for (ils = l2.begin(); ils != l2.end(); ils ++)
cout << *ils << endl;
l1.merge(l2);
cout << "\nlista l1 (wynik po dolaczeniu listy l2):\n";
for (ils = l1.begin(); ils != l1.end(); ils ++)
cout << *ils << endl;
cout << "\nlista l2 (wynik po dolaczeniu listy l2):\n";
for (ils = l2.begin(); ils != l2.end(); ils ++)
cout << *ils << endl;
l1.sort();
l1.unique();
cout << "\nlista l1 (wynik po wyeliminowaniu elementow zdublowanych):\n";
for (ils = l1.begin(); ils != l1.end(); ils ++)
cout << *ils << endl;
l1.sort(specialStringsCompare);
cout << "\nlista l1 (wynik po specjalnym sortowaniu)):\n";
for (ils = l1.begin(); ils != l1.end(); ils ++)
cout << *ils << endl;
l1.reverse();
cout << "\nlista l1 (wynik po odwroceniu listy):\n";
for (ils = l1.begin(); ils != l1.end(); ils ++)
cout << *ils << endl;
cout << "\nlista l1 (wypisywanie przy pomocy for_each i predykatu funkcyjnego):\n";
for_each(l1.begin(), l1.end(), printElement(cout));
//UWAGA: w funkcji for_each(,,) sa przecinki, a nie sredniki jak w instrukcji for(;;)
cout << "\nlista l1 (wypisywanie przy pomocy wskaznika do funkcji):\n";
for_each(l1.begin(), l1.end(), printElement2);
//min(class T, class T), max(class T, class T)
pairOfDoubles elem1(0.0, 1.0), elem2(2.0, 3.0);
swap(elem1, elem2);
9
cout << "\nelem1.x = " << elem1.x
<< ", elem1.x = " << elem1.y
<< ", elem2.x = " << elem2.x
<< ", elem2.y = " << elem2.y << endl;
return 0;
}
Zadanie 3.2. Wykorzystując blibliotekę STL napisać program narzędziowy sort. Program powinien — tak jak
w oryginale — udostępniać opcję -n przełączającą działanie programu w tryb sortowania numerycznego.
Przykładowe rozwiązanie:
#include <fstream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
#define MAX_LINE 65536
inline bool numericStringCompare(const string &s, const string &t) {
if (s.size() == t.size())
return s < t;
else
return s.size() < t.size();
}
int main(int argc, char** argv) {
char line[MAX_LINE];
vector <string> vp, vm;
ifstream
fin(argv[2], ios_base::binary);
ofstream fout(argv[3], ios_base::binary);
fin >> noskipws;
while (!fin.eof()) {
fin.getline(line, MAX_LINE);
if (string(argv[1]) == "-n"
&& line[0] == ’-’)
vm.push_back(string(line));
else
vp.push_back(string(line));
}
fin.close();
if (string(argv[1]) == "-n") {
sort(vm.begin(), vm.end(), numericStringCompare);
sort(vp.begin(), vp.end(), numericStringCompare);
}
else
sort(vp.begin(), vp.end());
for (int i = vm.size()-1; i >= 0 ; i --)
fout << vm[i] << endl;
for (int i = 0; i < vp.size(); i ++)
fout << vp[i] << endl;
fout.close();
return 0;
}
10
4. Przeciążanie funkcji
Zadanie 4.1. Przeanalizować działanie poniższego programu.
#include <iostream>
using namespace std;
void f(double x)
{ cout << "f(double x)" << endl; }
void f(int i)
{ cout << "f(int i)" << endl; }
void f(double x, double y)
{ cout << "f(double x, double y)" << endl; }
void f(int i, int j)
{ cout << "f(int i, int j)" << endl; }
void f(double x, double y=0.0) { cout << "f(double x, double y=0.0)" << endl; }
int main(int argc, char** argv) {
f(3);
f(3.0);
f((
int) 3.0);
f(3, 3);
f(3.0, 3.0);
//f(3, 3.0);
return 0;
}
5. Przeciążanie operatorów
Zadanie 5.1. Przeanalizować działanie poniższego programu.
#include <iostream>
class string {
private:
char
*p;
size_t
size;
public:
string(
const char str[]);
string(
const string &str);
˜string() {
delete[] p; }
string&
operator=(const string &str);
inline char& operator[](const int i) const { return p[i]; };
size_t length() {
return size; };
//
void toupper();
//
void tolower();
friend std::ostream& operator<<(std::ostream& os, const string& str);
};
string::string(
const char str[]) {
char *t = (char*) str;
while (*t != ’\0’)
t ++;
size = t - str;
p =
new char[size+1];
for (int i = 0; i <= size; i ++)
p[i]=str[i];
}
11
string::string(
const string &str) {
size = str.size;
p =
new char[size+1];
for (int i = 0; i <= size; i ++)
p[i]=str.p[i];
}
string& string::
operator=(const string &str) {
if (this != &str) {
delete [] p;
size = str.size;
p =
new char[size+1];
for (int i = 0; i <= size; i ++)
p[i]=str.p[i];
}
return *this;
}
std::ostream&
operator<<(std::ostream& os, const string& str) {
return os << str.p;
}
int main(int argc, char** argv) {
const char a[] = "Dzien jak c++odzien ;-)";
const char b[] = "Czy dziennik w szkole wieczorowej to nocnik?";
string s(a), t(b), u = s;
std::cout << "\n" << s
<< ", " << s[3]
<< ", " << s.length()
<< "\n" << t
<< ", " << t[3]
<< ", " << t.length()
<< "\n" << u
<< ", " << u[3]
<< ", " << u.length();
return 0;
}
Zadanie 5.2. Przeanalizować działanie poniższego programu.
#include <iostream>
using namespace std;
class matrix2x2 {
private:
double m[2][2];
public:
matrix2x2(
const double M[][2]);
matrix2x2(
double m00 = 0.0, double m01 = 0.0, double m10 = 0.0, double m11 = 0.0);
matrix2x2(
const matrix2x2 &M);
matrix2x2&
operator=(const matrix2x2 &M);
matrix2x2
operator-();
double det() const;
friend matrix2x2 operator+(const matrix2x2 &M1, const matrix2x2 &M2);
friend ostream&
operator<<(ostream& os, const matrix2x2 &M);
};
inline matrix2x2::matrix2x2(const double M[][2]) {
m[0][0] = M[0][0];
12
m[0][1] = M[0][1];
m[1][0] = M[1][0];
m[1][1] = M[1][1];
}
inline matrix2x2::matrix2x2(double m00, double m01, double m10, double m11) {
m[0][0] = m00;
m[0][1] = m01;
m[1][0] = m10;
m[1][1] = m11;
}
inline matrix2x2::matrix2x2(const matrix2x2 &M) {
m[0][0] = M.m[0][0];
m[0][1] = M.m[0][1];
m[1][0] = M.m[1][0];
m[1][1] = M.m[1][1];
}
inline matrix2x2& matrix2x2::operator=(const matrix2x2 &M) {
m[0][0] = M.m[0][0];
m[0][1] = M.m[0][1];
m[1][0] = M.m[1][0];
m[1][1] = M.m[1][1];
return *this;
}
inline matrix2x2 matrix2x2::operator-() {
matrix2x2 M;
M.m[0][0] = -m[0][0];
M.m[0][1] = -m[0][1];
M.m[1][0] = -m[1][0];
M.m[1][1] = -m[1][1];
return M;
}
inline double matrix2x2::det() const {
return m[0][0]*m[1][1] - m[0][1]*m[1][0];
}
inline matrix2x2 operator+(const matrix2x2 &M1, const matrix2x2 &M2) {
matrix2x2 M = M1;
M.m[0][0] += M2.m[0][0];
M.m[0][1] += M2.m[0][1];
M.m[1][0] += M2.m[1][0];
M.m[1][1] += M2.m[1][1];
return M;
}
ostream&
operator<<(ostream& os, const matrix2x2 &M) {
return os << "\n" << M.m[0][0]
<< ", " << M.m[0][1]
<< "\n" << M.m[1][0]
<< ", " << M.m[1][1]
<< "\n";
}
int main(int argc, char** argv) {
const double tab[][2]= {{1.5, 2.5}, {3.5, 4.5}};
matrix2x2 A(tab), B(1.0, 0.0, 0.0, -1.0), C = A + B, D;
D = -C;
13
cout << "\nMacierz A: " << A
<< ", macierz B: " << B
<< ", macierz C: " << C
<< ", macierz D: " << D
<< ", wyznacznik macierzy A: " << A.det()
//-2.0
<< ", wyznacznik macierzy B: " << B.det()
//-1.0
<< ", wyznacznik macierzy C: " << C.det()
// 0.0
<< ", wyznacznik macierzy D: " << D.det(); // 0.0
return 0;
}
Zadanie 5.3. Utworzyć klasę matrix3x3 reprezentująca macierze kwadratowe wymiaru 3 × 3 o wyrazach rzeczy-
wistych (zob. zad. 5.2).
6. Dalej o klasach
Zadanie 6.1.
Zaobserwować, na poniższym przykładzie, jakie znaczenie w definicji klasy ma słowo kluczowe
explicit
.
#include <iostream>
using namespace std;
class test {
private:
int private_int;
public:
explicit test(
const int& = int());
test explicit_test();
test&
operator++();
test&
operator++(int);
friend test operator+(const test& a, const test& b);
};
test::test(
const int& i) : private_int(i) { }
test test::explicit_test() {
return 0; }
test& test::
operator++() {
cout << "przedrostkowy\n";
++
private_int;
return *this;
}
test& test::
operator++(int) {
cout << "przyrostkowy\n";
private_int ++;
return *this;
}
inline test operator+(const test& a, const test& b) {
test c;
c.
private_int = a.private_int + b.private_int;
return c;
}
int main(int argc, char** argv) {
test x(1), y = test(), z = x + y, t;
z ++; ++ z;
14
return 0;
}
Zadanie 6.2. Zaobserwować, na poniższym przykładzie, jakie znaczenie w definicji klasy ma słowo kluczowe const.
#include <iostream>
#include <complex>
#include <cmath>
using namespace std;
int I;
class test {
private:
int i;
public:
void f1() const;
void f2() const;
void f3();
};
//void test::f0() const { i = 1; }
void test::f1() const {
}
void test::f2() const { I = 1;
}
void test::f3()
{ i = 1;
}
void f1(int i)
{ i = 1;
}
void f2(int &i)
{ i = 1;
}
void f3(int *i)
{ *i = 1; }
void f4(const int i)
{ i = 1;
}
void f5(const int &i) { i = 1;
}
void f6(const int* i) { *i = 1; } //wskaznik do stalego int-a...
void f7(int const* i) { *i = 1; } //wskaznik do stalego int-a...
void f8(int *const i) { *i = 1; } //staly wskaznik do int-a...
int main(int argc, char** argv) {
test t;
t.f1();
t.f2();
t.f3();
int k;
k = 0; f1(k);
cout << k << endl;
k = 0; f2(k);
cout << k << endl;
k = 0; f3(&k); cout << k << endl;
k = 0; f8(&k); cout << k << endl;
return 0;
}
7. Dziedziczenie klas
Zadanie 7.1. Przeanalizować działanie poniższego programu.
#include <iostream>
using namespace std;
class abstractFigure {
public:
virtual void
scale(
const double s) = 0;
15
virtual double area() = 0;
virtual double length() = 0;
};
class square : public abstractFigure {
protected: //przy ‘private’ bylby blad!
double a;
public:
square(
const double &A = 0) : a(A) {}
void scale(const double s) { a *= s; }
double area()
{
return a * a; }
double length() { return 4 * a; }
};
class rectangle : public square {
protected:
double b;
public:
rectangle(
const double &A = 0, const double &B = 0) : b(B) { a = A;}
void scale(const double s) { a *= s; b *= s; }
double area()
{
return a * b; }
double length() { return 2*a + 2*b; }
};
//ROWNOLEGLOBOK
class parallelogram : public rectangle {
private:
double h;
public:
parallelogram(
const double &A = 0, const double &B = 0, const double &H = 0)
: h(H) { a = A; b = B; }
void scale(const double s) { rectangle::scale(s); h *= s; }
//wykorzystujemy skalowanie z ‘rectangle’
double area() { return a * h; }
//nie musimy pisac metody ‘length’,
//bo bylaby taka sama jak w klasie ‘rectangle’
};
int main(int argc, char** argv) {
//figure
F; //Nie mozna tworzc obiektow klas abstrakcyjnych!
//(takie klasy nie maja nawet konstruktorow)
square
S(1);
rectangle
R(1,2);
parallelogram
P(1,2,3);
cout << "\n" << S.area()
<< ", " << S.length()
<< "\n" << R.area()
<< ", " << R.length()
<< "\n" << P.area()
<< ", " << P.length();
//cout << S.a; spowoduje blad przy kompilacji
//(bo nie ma dostepu do skladowych prywatnych i chronionych)
return 0;
}
Zadanie 7.2. Przeanalizować działanie poniższego programu.
#include <iostream>
using namespace std;
16
class animal {
public:
char* name() { return "animal"; }
};
class bird : public animal {
public:
char* name() { return "bird"; }
};
class hen : public bird {
public:
char* name()
{
return "hen"; }
int
numberOfHands() {
return 0; }
int
numberOfWings() {
return 2; }
int
numberOfLegs()
{
return 2; }
bool
canSwim()
{
return false; }
};
//ssak...
class mammal : public animal {
public:
char* name() { return "mammal"; }
};
class cow : public mammal {
public:
char* name()
{
return "cow"; }
int
numberOfHands() {
return 0; }
int
numberOfWings() {
return 0; }
int
numberOfLegs()
{
return 4; }
bool
canSwim()
{
return false; }
};
class cat : public mammal {
public:
char* name()
{
return "cat"; }
int
numberOfHands() {
return 0; }
int
numberOfWings() {
return 0; }
int
numberOfLegs()
{
return 4; }
bool
canSwim()
{
return false; }
};
class dog : public mammal {
public:
char* name()
{
return "dog"; }
int
numberOfHands() {
return 0; }
int
numberOfWings() {
return 0; }
int
numberOfLegs()
{
return 4; }
bool
canSwim()
{
return true; }
};
int main(int argc, char** argv) {
animal A;
bird
B;
cow
C;
dog
D;
hen
H; // kura...
cat
K;
cout << "\n" << A.name()
<< "\n" << B.name()
17
<< "\n" << C.name()
<< ", " << C.numberOfHands()
<< ", " << C.numberOfWings()
<< ", " << C.numberOfLegs()
<< ", " << C.canSwim()
<< "\n" << D.name()
<< ", " << D.numberOfHands()
<< ", " << D.numberOfWings()
<< ", " << D.numberOfLegs()
<< ", " << D.canSwim()
<< "\n" << H.name()
<< ", " << H.numberOfHands()
<< ", " << H.numberOfWings()
<< ", " << H.numberOfLegs()
<< ", " << H.canSwim()
<< "\n" << K.name()
<< ", " << K.numberOfHands()
<< ", " << K.numberOfWings()
<< ", " << K.numberOfLegs()
<< ", " << K.canSwim();
return 0;
}
Zadanie 7.3. Stosując dziedziczenie klas utworzyć klasy modelujące prostą „hierarchię” pojazdów. Utworzone klasy
powinny zawierać metody zwracające nazwę pojazdu, ilość kół pojazdu, ilość drzwi pojazdu oraz rodzaj zastosowanego
napędu. Hierarchia pojazdów powinna „rozpoczynać” się od pojazdu abstrakcyjnego (zob. zad. 7.2).
8. Klasy szablonowe
Zadanie 8.1. Utworzyć klasę szablonową realizującą interfejs kolejki.
Przykładowe rozwiązanie:
#ifndef QUEUE_H
#define QUEUE_H
template <typename Type> class queue {
public:
class queue_element {
public:
Type
elem;
queue_element *next;
queue_element *prev;
};
private:
size_t
queue_size;
queue_element *first, *last;
public:
explicit queue() { queue_size = 0; first = NULL; last = NULL; };
bool empty()
const;
size_t size()
const;
Type front()
const;
Type back()
const;
void push(const Type& elem);
void pop();
void clear(); //tego nie ma w interfejsie kolejki z STL-a
};
18
template <class Type> bool queue<Type>::empty() const {
return (first == NULL);
}
template <class Type> size_t queue<Type>::size() const {
return queue_size;
}
template <class Type> Type queue<Type>::front() const {
Type elem;
if (!empty())
return first->elem;
return elem;
}
template <class Type> Type queue<Type>::back() const {
Type elem;
if (!empty())
return last->elem;
return elem;
}
template <class Type> void queue<Type>::push(const Type& elem) {
queue_element *temp =
new queue_element;
if (temp) {
queue_size ++;
temp->elem = elem;
if (empty()) {
temp->prev = temp->next = NULL;
first = last = temp;
}
else {
temp->prev = last;
temp->next = NULL;
last->next = temp;
last = temp;
}
}
}
template <class Type> void queue<Type>::pop() {
queue_element *second;
if (first != NULL) {
second = first->next;
if (second != NULL)
second->prev = NULL;
}
delete first;
queue_size --;
first = second;
}
19
template <class Type> void queue<Type>::clear() {
while (!empty()) {
pop();
}
}
#endif
Zadanie 8.2. Wykorzystując utworzoną klasę szablonową kolejki napisać grę „saper”.
Przykładowe rozwiązanie:
#include <iostream>
#include <queue>
#include <cstdlib>
using namespace std;
#define X 20
#define Y 10
class miner {
public:
struct pairOfInt { //to moze sie przydac w metodzie ‘check’...
int x, y;
pairOfInt(
const int &xx = 0, const int &yy = 0) : x(xx), y(yy) {};
};
miner(
const int &nn);
void check(const int &, const int &);
const bool& solved
()
const { return s; }
const bool& finished() const { return f; }
private:
int
n, rem, board[X+2][Y+2]; //tablica z ,,zaporami’’ (z wartownikiem)...
bool s, f;
friend ostream& operator<<(ostream& os, const miner &M); //rysuje plansze...
};
miner::miner(
const int &nn) {
int x, y;
n = nn;
rem = X*Y;
s = false;
f = false;
for (y = 1; y <= Y; y ++)
for (x = 1; x <= X; x ++)
board[x][y] = -2; //puste pole...
for (y = 0; y <= Y+1; y ++)
board[0][y] = board[X+1][y] = -3; //sciana...
for (x = 0; x <= X+1; x ++)
board[x][0] = board[x][Y+1] = -3; //sciana...
while (n) {
x = (rand() % X) + 1;
y = (rand() % Y) + 1;
if (board[x][y] == -2) {
board[x][y] = -1;
n --;
}
}
n = nn;
}
20
void miner::check(const int &x, const int &y) {
int xx, yy, ss;
pairOfInt
t;
queue<pairOfInt> Q;
if (board[x][y] > 0)
return;
if (board[x][y] == -1) {
s = false;
f = true;
return;
}
Q.push(pairOfInt(x,y));
while (!Q.empty()) {
t = Q.front();
Q.pop();
ss = 0;
if (board[t.x][t.y] == -2) {
for (yy = t.y-1; yy <= t.y+1; yy ++)
for (xx = t.x-1; xx <= t.x+1; xx ++)
if ((board[xx][yy] == -1)
&& ((xx != t.x) || (yy != t.y)))
ss ++;
board[t.x][t.y] = ss;
if (!ss)
for (yy = t.y-1; yy <= t.y+1; yy ++)
for (xx = t.x-1; xx <= t.x+1; xx ++)
if ((board[xx][yy] == -2) && ((xx != t.x) || (yy != t.y)))
Q.push(pairOfInt(xx,yy));
rem --;
}
}
if (rem <= n)
s = f = true;
}
ostream&
operator<<(ostream &os, const miner &M) {
int
x, y;
char c;
for (y = 1; y <= Y; y ++) {
for (x = 1; x <= X; x ++) {
c = (M.board[x][y]>=0 ? (
char)(M.board[x][y]+’0’) : ’ ’);
os << c;
}
os << ’|’ << y << endl;
}
for (x = 1; x <= X; x ++)
os << ’-’;
os << ’+’ << endl;
for (x = 1; x <= X; x ++) {
c = (
char)(x + ’a’ - 1);
os << c;
}
os << endl;
return os;
}
int main(int argc, char** argv) {
char
c;
int
i;
21
cout << "Podaj ilosc bomb: ";
cin
>> i;
miner M(i);
while (!M.finished()) {
cout << M << endl << "Twoj ruch (np. e4): ";
cin
>> c >> i;
M.check((
int)(c-’a’+1), i);
}
cout << M;
if (M.solved())
cout << "Gratulacje!" << endl;
else
cout << "Buuu..." << endl;
return 0;
}
Zadanie 8.3. Przerobić klasę matrix2x2 z zadania 5.2 na klasę szablonową.
Przykładowe rozwiązanie:
#include <iostream>
using namespace std;
template <typename type> class matrix2x2 {
private:
type m[2][2];
public:
matrix2x2(
const type M[][2]);
matrix2x2(type m00 = 0.0, type m01 = 0.0, type m10 = 0.0, type m11 = 0.0);
matrix2x2(
const matrix2x2<type> &M);
matrix2x2<type>&
operator=(const matrix2x2<type> &M);
matrix2x2<type>
operator-();
type det()
const;
template <typename type_> friend matrix2x2<type_> operator+
(
const matrix2x2<type_> &M1, const matrix2x2<type_> &M2);
template <typename type_> friend ostream&
operator<<
(ostream& os,
const matrix2x2<type_> &M);
};
template <typename type> inline matrix2x2<type>::matrix2x2(const type M[][2]) {
m[0][0] = M[0][0];
m[0][1] = M[0][1];
m[1][0] = M[1][0];
m[1][1] = M[1][1];
}
template <typename type> inline matrix2x2<type>::matrix2x2(
type m00, type m01, type m10, type m11) {
m[0][0] = m00;
m[0][1] = m01;
m[1][0] = m10;
m[1][1] = m11;
}
template <typename type> inline matrix2x2<type>::matrix2x2(const matrix2x2<type> &M) {
m[0][0] = M.m[0][0];
m[0][1] = M.m[0][1];
m[1][0] = M.m[1][0];
m[1][1] = M.m[1][1];
}
22
template <typename type> inline matrix2x2<type>& matrix2x2<type>::operator=(
const matrix2x2<type> &M) {
m[0][0] = M.m[0][0];
m[0][1] = M.m[0][1];
m[1][0] = M.m[1][0];
m[1][1] = M.m[1][1];
return *this;
}
template <typename type> inline matrix2x2<type> matrix2x2<type>::operator-() {
matrix2x2<type> M;
M.m[0][0] = -m[0][0];
M.m[0][1] = -m[0][1];
M.m[1][0] = -m[1][0];
M.m[1][1] = -m[1][1];
return M;
}
template <typename type> inline type matrix2x2<type>::det() const {
return m[0][0]*m[1][1] - m[0][1]*m[1][0];
}
template <typename type> inline matrix2x2<type> operator+(
const matrix2x2<type> &M1, const matrix2x2<type> &M2) {
matrix2x2<type> M = M1;
M.m[0][0] += M2.m[0][0];
M.m[0][1] += M2.m[0][1];
M.m[1][0] += M2.m[1][0];
M.m[1][1] += M2.m[1][1];
return M;
}
template <typename type> ostream& operator<<(ostream& os, const matrix2x2<type> &M) {
return os << "\n" << M.m[0][0]
<< ", " << M.m[0][1]
<< "\n" << M.m[1][0]
<< ", " << M.m[1][1]
<< "\n";
}
int main(int argc, char** argv) {
const double tab[][2]= {{1.5, 2.5}, {3.5, 4.5}};
matrix2x2<
double> A(tab), B(1.0, 0.0, 0.0, -1.0), C = A + B, D;
D = -C;
cout << "\nMacierz A: " << A
<< ", macierz B: " << B
<< ", macierz C: " << C
<< ", macierz D: " << D
<< ", wyznacznik macierzy A: " << A.det()
<< ", wyznacznik macierzy B: " << B.det()
<< ", wyznacznik macierzy C: " << C.det()
<< ", wyznacznik macierzy D: " << D.det();
return 0;
}
23
9. Zręby klas
Zadanie 9.1. Utworzyć zręb umożliwiający wygodną implementację algorytmów grafowych.
Przykładowe rozwiązanie:
#ifndef GRAPH_H
#define GRAPH_H
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
class vertice
{
public:
vector<
int> successors, predecessors;
size_t degree()
const { return successors.size()+predecessors.size(); }
size_t outDegree()
const { return successors.size(); }
size_t inDegree()
const { return predecessors.size(); }
};
class graph
{
private:
size_t _numberOfEdges;
public:
vector<vertice> vertices;
graph(size_t size = 0);
size_t numberOfVertices()
const { return vertices.size(); }
size_t numberOfEdges()
const { return _numberOfEdges; }
void insertEdge(int u, int v);
};
inline graph::graph(size_t size)
{
vertices.resize(size);
_numberOfEdges = 0;
}
inline void graph::insertEdge(int u, int v)
{
vertices[u].successors.push_back(v);
vertices[v].predecessors.push_back(u);
_numberOfEdges ++;
}
template <class type> class verticeMap
{
private:
vector<type> _map;
public:
verticeMap(
const graph& G, type value=type())
{ _map.resize(G.vertices.size(), value); }
size_t size() {
return _map.size(); }
type&
operator[](const int i) { return _map[i]; }
};
template <class type> class edgeMap
{
typedef vector<type> vectorType;
24
private:
vector<vectorType> _map;
public:
edgeMap(
const graph& G, type t=type());
size_t size() {
return _map.size(); }
vectorType&
operator[](const int i) { return _map[i]; }
template <class type_>
friend void load(graph& G, edgeMap<type_>& c, char * filename);
};
template <class type> inline edgeMap<type>::edgeMap(const graph& G, type value)
{
_map.resize(G.vertices.size());
for (int v = 0; v < _map.size(); v ++)
_map[v].resize(G.vertices[v].successors.size(), value);
}
template <class type> void load(graph& G, edgeMap<type>& c, char * filename)
{
int numberOfVertices, numberOfEdges, u, v;
type t;
ifstream file(filename, ios::binary);
file >> numberOfVertices >> numberOfEdges;
G.vertices.resize(numberOfVertices);
c._map.resize(numberOfVertices);
for (v = 0; v < numberOfVertices; v ++)
{
G.vertices[v].successors.clear();
G.vertices[v].predecessors.clear();
c._map[v].clear();
}
for (int i = 0; i < numberOfEdges; i ++)
{
file >> u >> v >> t;
G.insertEdge(u, v);
c[u].push_back(t);
}
file.close();
}
#endif
Zadanie 9.2. Wykorzystać utworzony zręb do zaimplementowania programu wypisującego wszystkie ścieżki proste
w grafie.
Przykładowe rozwiązanie:
#include <iostream>
#include "graph.h"
using namespace std;
struct label
{
int _v_, u;
bool onPath;
label (
int _v__ = int(), int u_ = int(), bool onPath_ = bool()) :
_v_(_v__), u(u_), onPath(onPath_) { }
//friend istream& operator>>(istream& is, label &l);
};
25
int main(int argc, char ** argv)
{
graph G;
edgeMap<
double> c(G);
load(G, c, argv[1]);
const int s = 0;
const int t = G.vertices.size()-1;
verticeMap<label> L(G, label(-1, 0, false));
L[s] = label(-1, 0, true);
int n = 0, u = s, v;
double cost;
do
{
do
{
do
{
L[u]._v_ ++;
}
while((L[u]._v_ < G.vertices[u].successors.size()) &&
L[G.vertices[u].successors[L[u]._v_]].onPath);
if ((L[u]._v_ < G.vertices[u].successors.size()) &&
!L[G.vertices[u].successors[L[u]._v_]].onPath)
{
L[G.vertices[u].successors[L[u]._v_]].onPath = true;
L[G.vertices[u].successors[L[u]._v_]].u = u;
u = G.vertices[u].successors[L[u]._v_];
}
else
{
if (L[u].u == u)
break;
L[u]._v_ = -1;
L[u].onPath = false;
u = L[u].u;
}
}
while(u != t);
if (L[u].u == u)
break;
cost = 0.0;
u = s;
n ++;
do
{
cout << u << " --> " << flush;
cost += c[u][L[u]._v_];
u = G.vertices[u].successors[L[u]._v_];
}
while(u != t);
cout << t << ": koszt = " << cost << endl;
}
while (G.vertices[s].successors[L[s]._v_] != s);
26
cout << "Calkowita liczba ciezek prostych z wierzcholka zrodlowego " << s
<< " do wierzcholka docelowego " << t << ": " << n << endl;
}
10. Podstawy zrębu Qt 4.5
Zadanie 10.1. Przeanalizować działanie poniższego programu.
Plik qt.pro:
TARGET = qt
TEMPLATE = app
SOURCES += main.cpp\
widget.cpp
HEADERS
+= widget.h
FORMS
+= widget.ui
Plik widget.ui:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>WidgetClass</class>
<widget class="QWidget" name="WidgetClass">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>200</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>300</width>
<height>200</height>
</size>
</property>
<property name="windowTitle">
<string>Test zrebu Qt</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
27
</item>
<item row="2" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>82</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>87</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="1">
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>Zamknij</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="pushButton_2">
<property name="text">
<string>Info</string>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>
<connections>
<connection>
<sender>pushButton</sender>
<signal>clicked()</signal>
<receiver>WidgetClass</receiver>
<slot>close()</slot>
<hints>
<hint type="sourcelabel">
<x>161</x>
<y>173</y>
</hint>
<hint type="destinationlabel">
<x>108</x>
<y>94</y>
</hint>
</hints>
</connection>
</connections>
28
</ui>
Plik main.cpp:
#include <QtGui/QApplication>
#include "widget.h"
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Plik widget.h:
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
#include <QMouseEvent>
#include <QPainter>
#include <QMessageBox>
namespace Ui {
class WidgetClass;
}
class Widget : public QWidget {
Q_OBJECT
public:
Widget(QWidget *parent = 0);
˜Widget();
void paintEvent(QPaintEvent *event);
//zdarzenie odmalowania okna
void mouseMoveEvent(QMouseEvent *event);
//zdarzenie ruchu kursora myszy
void mousePressEvent(QMouseEvent *event); //zdarzenie nacisniecia przycisku myszy
private:
Ui::WidgetClass *ui;
private slots:
void on_pushButton_2_clicked();
};
#endif // WIDGET_H
Plik widget.cpp:
#include "widget.h"
#include "ui_widget.h"
#define X_NO_SEGS 20
#define Y_NO_SEGS 15
#define X_OFFSET
10
#define Y_OFFSET
10
Widget::Widget(QWidget *parent) : QWidget(parent), ui(
new Ui::WidgetClass) {
ui->setupUi(
this);
this->setMouseTracking(true); //!!!
}
Widget::˜Widget() {
delete ui;
}
29
void Widget::paintEvent(QPaintEvent *event) {
int windowWidth
=
this->geometry().width()
- 2*X_OFFSET;
int windowHeight = this->geometry().height() - 2*Y_OFFSET;
int min = (windowWidth > windowHeight ? windowHeight : windowWidth);
int segmentWidth = min / X_NO_SEGS, segmentHeight = min / Y_NO_SEGS;
QPainter painter(
this);
for (int y = 0; y < Y_NO_SEGS; y ++)
for (int x = 0; x < X_NO_SEGS; x ++)
painter.drawRect(X_OFFSET + (windowWidth -min) / 2 + segmentWidth*x,
Y_OFFSET + (windowHeight-min) / 2 + segmentHeight*y,
segmentWidth, segmentHeight);
}
void Widget::mouseMoveEvent(QMouseEvent *event) {
ui->label->setText(QString(
"Wspolrzedne wskaznika myszy: (%1, %2)").arg(event->x()).arg(event->y()));
}
void Widget::mousePressEvent(QMouseEvent *event) {
int windowWidth
=
this->geometry().width()
- 2*X_OFFSET;
int windowHeight = this->geometry().height() - 2*Y_OFFSET;
int min = (windowWidth > windowHeight ? windowHeight : windowWidth);
int segmentWidth = min / X_NO_SEGS, segmentHeight = min / Y_NO_SEGS;
int x = (event->x() - X_OFFSET - (windowWidth -min) / 2) / segmentWidth;
int y = (event->y() - Y_OFFSET - (windowHeight-min) / 2) / segmentHeight;
if ((x >= 0) && (x < X_NO_SEGS) && (y >= 0) && (y < Y_NO_SEGS))
ui->label_2->setText(QString("Kliknieto na polu: (%1, %2)").arg(x).arg(y));
}
void Widget::on_pushButton_2_clicked()
{
QMessageBox::information(
this, "Info",
"Moj pierwszy program wykorzystujacy zreb Qt...");
}
11. Zadania zaliczeniowe
Zadanie 11.1. Przy pomocy zrębu Qt utworzyć graficzny interfejs dla gry „kółko krzyżyk” (zob. zad. 11.8).
Zadanie 11.2. Przy pomocy zrębu Qt utworzyć graficzny interfejs dla gry „gomoku” (zob. zad. 11.9).
Zadanie 11.3. Przy pomocy zrębu Qt utworzyć graficzny interfejs dla gry „czwórki” (zob. zad. 11.10).
Zadanie 11.4. Przy pomocy zrębu Qt utworzyć graficzny interfejs dla gry „saper” (zob. zad. 8.2).
Zadanie 11.5. Przy pomocy zrębu Qt utworzyć narzędzie do wizualizacji grafów (zob. zad. 9.1).
Zadanie 11.6. Wykorzystać zaprezentowany zręb grafowy do implementacji algorytmu Belmana-Forda (zob. zad.
9.1).
Zadanie 11.7. Wykorzystując klasę kolejki priorytetowej oraz zaprezentowany zręb grafowy zaimplementować
algorytm Dijkstry (zob. zad. 11.15 i 9.1).
Zadanie 11.8. Utworzyć klasę realizującą grę „kółko–krzyżyk” z tekstowym interfejsem użytkownika (gra użyt-
kownik kontra komputer). Komputer nie powinien dać się ograć!
Zadanie 11.9. Utworzyć klasę realizującą grę „gomoku” (na obszarze wymiaru 20 × 20) z tekstowym interfejsem
użytkownika (gra użytkownik kontra komputer).
30
Zadanie 11.10. Utworzyć klasę realizującą grę „czwórki” z tekstowym interfejsem użytkownika (gra użytkownik
kontra komputer).
Zadanie 11.11.
Utworzyć klasę generującą labirynty (o podanych wymiarach) oraz znajdującą przejście przez
dowolny labirynt (o ile takie przejście istnieje).
Zadanie 11.12. Utworzyć klasę macierzy wymiaru n × k (zob. zad. 5.2). Funkcje zaprzyjaźnine realizujące operacje
dodawania, odejmowania i mnożenia macierzy powinny zgłaszać odpowiednie wyjątki w przypadku, gdy dana operacja
nie jest wykonalna. Zastosować dziedziczenie klas w implementacji metody obliczającej wyznacznik macierzy oraz
w metodzie zwracającej macierz odwrotną.
Zadanie 11.13. Utworzyć klasę realizującą podstawowe działania arytmetyczne na dowolnie dużych (i dowolnie
małych) liczbach całkowitych.
Zadanie 11.14. Utworzyć klasę realizującą podstawowe działania arytmetyczne na liczbach wymiernych. Obiekty
utworzonej klasy powinny zapewniać dokładną reprezentację liczb wymiernych — wykorzystać klase liczb calkowitych
z zadania 11.13.
Zadanie 11.15. Utworzyć wydajną(!) klasę szablonową realizującą podstawowy interfejs kolejki priorytetowej (zob.
zad. 8.1).
12. Bonus
Zadanie 12.1. Przeanalizować działanie poniższego zwycięzkiego programu z roku 2005, napisanego przez Óscara
Toledo w ramach The International Obfuscated C Code Contest (w skrócie IOCCC), czyli Międzynarodowego Kon-
kursu na Najbardziej Zamroczony Kod C (zob. http://www.ioccc.org/) oraz przyjrzeć się kodowi źródłowemu
oglądanemu „do góry nogami” :-)
31
#define
F getchar())
#define H(z)*n++=z;
#include
<setjmp.h>
#define v main(0,0,0
#define Z while(
#define _ if(
#define o(d)(S=63,u[l]=0,l[d]=6ˆe,q=1e4>v,0),l[d]=0,u[l]=eˆ6,S=b,q)
#define I(H,n) { _ r=l[x=H],!r|(rˆe)<-1){ _ j=u[l],-7==r|6==r\
){ n; e=˜e; return 1e5-443*f; } u[l]=0,t=j+1,i=j-1; _!i&89<\
x)i=j,t=6; _-1==t&30>x)t=j,i=-7; Z++i<t){ d =0; S&= 63; \
a=((jˆe)!=1?6!=(jˆe)?O[32+x/10]-O[u/10+32]-q:(S|=6!=j?8\
:1,2==u-x)*9+9*(x-u==2):(d=1==j?x-u:u-x)/8+!(!((x-u)%\
10)|r)*99+(j==1?90<x:29>x)*(9*O[28+i]-288))+O[r+28\
]*9-288+O[x%10+33]-f-O[33+u%10]; x[l]=i; S|=(21=\
=u|21==x)*2+(u==28|28==x)*4+(91==u|x==91)*16+32\
*(u==98|x==98)+(20==d)*64*x; a-=k>f?main(a,f+1\
,M,k):0; _ i==c&u==h&!f&N&a>-1e4&x==y)longjm\
p(z,1); S=b; _!N|f&&(a>M||!f&a==M&&1&rand()\
)){ _!f){ _ k){ c=i; h=u; y=x; } } else _ \
L-a<N){ n; e=˜e; u[l]=j; x[l]=r; return\
a; } M=a; } } x[l]=r; u[l]=j; n; } }
typedef int G; char J [ 78 ], O [ ]
=
"HRQAMS#-smaqrh[UTZYTU[|TBA("
"$#(ABT|ba‘gg‘ab8>GK[_‘fFDZXEYR"
"L\t####"
"##B#A#@#G#F#E#D#K\t\3Zlv#tjm"
"\3J#tjm\3Pwb"
"ofnbwf\3Joofdbo\3)&‘&‘.&‘&‘"
"#+&g*\t"; G y,
c,h,e,S,*s,l[149]; jmp_buf z
; G main(G L,G f,
G N,G k){ G u=99,p,q,r,j,i,x
,t,a,b=S,d,M=-1e9
; char *n; if( *l){ e=˜e; Z
u >21){ q= l[--u]ˆe;
_!-- q){ _!l[p=e?u-10:u+10]){
I(p,)_ e?u>80
& !l[p
-=10]:u<39&!l[p+=10])I(p,)} _ l[p=e?u-11:9+u]
)I(p,)
else _ u-1==S>>6){ l[u-1]=0; I(p,l[u-1]=-2ˆe);
} _ l[
p=e?u-9:11+u])I(p,)else _ S>>6==1+u){ l[1+u]=0; I(p,l
[1+u]=eˆ-2); } } _!--q){ n=O+41; Z++n<50+O)I(u+80-*n,
)} _ 0<q&4>q){
n=q==2?53+O:O+49; Z++n<O+(q!=1)*4+54
){ p=u; do I(p-=*n-80,)Z!p[l]); } } _ 4==q){ n=49+O
; Z++n<O+58)I(u-*n+80,)_ e&!(S&24)|!e&!(S&3)
&&
!l[u-2]&!l[u-1]&!l[u-3]&&o(u)&&o(u-1)){ l[u-1]=4
ˆe; l[u-4]=0; I(u-2,l[u-1]=0; l[u-4]=eˆ4); } _
e&!(S&40)|!e&!(S&5)
&&!l[u+1]&!l[2+u]&&o(u)&&
o(1+u)){ l[u+1]=eˆ4; l[3+u]=0;
I(u+2,l[1+u
]=0; l[u+3]=4ˆe); } } } e=˜e;
return M; }
Z h<130){l[h]=-(21>h|98<h|2
>(h+1 )%
10); O[h++]ˆ=3; } n=O +14;
s=20+l; Z
++s<29+l){ 10[s]=1; 70[s]=˜
( * s = *
n++ -+84); 60 [ s] =-2; } Z
n=J){ puts
(58+O); u=19; Z++u<100){ H(32)_!( u%10
))H(32)H(O[7+l[u]])_(9+u)%10>7){ H(58
-u/10)H(32)_ u&1)puts(n=J); } } puts
(O+58); _-1e4 >v , 1)){ e=˜e; puts
(O+(v,0)> 1e4?e?90:82:96)); break
; } _ 1<L&e) { d=v,2+L); printf
(O+114,h%10+64,58-h/10,y%10+64
,58 -y/10,d); } else{ putchar
(62+e); h= (95 & F-44; c=l[h
+=(56-F *10]; y=(95&F-44; y
+=(56-F*10; Z 10!=(u=(95
&F)){ c=5; Z--c>1&&u!=c
[O]); c=eˆc-7; } } _!
setjmp(z)){ v+1,1);
puts(
106+
O); }
} Z
10!=
F; }
32