7. gyakorlat - megoldások
1. feladat. Definiáljunk egy Teglalap osztályt, és származtassuk
ebből a Negyzet osztályt, melyek téglalapokat ill. négyzeteket
reprezentálnak.
A Teglalap osztály adattagjai reprezentálják a magasságot ill.
szélességet, és rendelkezzen a következő tagfüggvényekkel:
- konstruktor két paraméterrel,
- függvények a magasság és szélesség lekérdezésére
és megváltoztatására,
- függvények a terület és kerület kiszámítására.
A Negyzet osztály rendelkezzen egy egyparaméterű
konstruktorral, amely a Teglalap osztály konstruktorán
alapszik. Ezen felül legyenek ugyanazok a tagfüggvényei, mint a
Teglalap osztálynak, de a magasságot ill. a szélességet megváltoztató
függvények változtassák meg mindkettőt.
Megoldás:
teglalap.h
#ifndef TEGLALAP_H
#define TEGLALAP_H
class Teglalap {
protected:
double magassag;
double szelesseg;
public:
Teglalap(double magassag, double szelesseg);
double getMagassag() const;
double getSzelesseg() const;
virtual void setMagassag(double magassag);
virtual void setSzelesseg(double szelesseg);
double terulet() const;
double kerulet() const;
virtual ~Teglalap() = default;
};
#endif // TEGLALAP_H
teglalap.cpp
#include "teglalap.h"
Teglalap::Teglalap(double magassagParam, double szelessegParam)
: magassag(magassagParam), szelesseg(szelessegParam) {}
double Teglalap::getMagassag() const {
return magassag;
}
double Teglalap::getSzelesseg() const {
return szelesseg;
}
void Teglalap::setMagassag(double magassagParam) {
magassag = magassagParam;
}
void Teglalap::setSzelesseg(double szelessegParam) {
szelesseg = szelessegParam;
}
double Teglalap::terulet() const {
return magassag * szelesseg;
}
double Teglalap::kerulet() const {
return 2 * (magassag + szelesseg);
}
negyzet.h
#ifndef NEGYZET_H
#define NEGYZET_H
#include "teglalap.h"
class Negyzet : public Teglalap {
public:
Negyzet(double oldal);
void setMagassag(double oldal);
void setSzelesseg(double oldal);
};
#endif // NEGYZET_H
negyzet.cpp
#include "negyzet.h"
Negyzet::Negyzet(double oldal) : Teglalap(oldal, oldal) {}
void Negyzet::setMagassag(double oldal) {
magassag = oldal;
szelesseg = oldal;
}
void Negyzet::setSzelesseg(double oldal) {
magassag = oldal;
szelesseg = oldal;
}
3. feladat. Definiáljunk egy Alakzat osztályt, amely
egy síkidomot reprezentál. Legyenek adattagjai, melyek a síkidom pozícióját
határozzák meg. Származtassunk belőle
különböző osztályokat, pl. kör, téglalap, paralelogramma, sokszög stb. osztályokat.
Legyenek az Alakzat osztálynak tisztán virtuális terulet és kerulet tagfüggvényei, és valósítsuk meg ezeket a származtatott osztályokban.
Deklaráljunk olyan tömböt/tárolót, amelyben különböző típusú síkidomokat tárolhatunk.
Megoldás:
alakzat.h
#ifndef ALAKZAT_H
#define ALAKZAT_H
#include "point.h"
using namespace std;
namespace bme {
class Alakzat {
protected:
Point p;
public:
Alakzat(double x, double y) : p(x, y) {}
virtual double terulet() const = 0;
virtual double kerulet() const = 0;
Point pozicio() const { return p; };
virtual ~Alakzat() = default;
};
}
#endif // ALAKZAT_H
teglalap.h
#ifndef TEGLALAP_H
#define TEGLALAP_H
#include "alakzat.h"
namespace bme {
class Teglalap : public Alakzat {
private:
double magassag;
double szelesseg;
public:
Teglalap(double x, double y, double magassag, double szelesseg);
double terulet() const override;
double kerulet() const override;
};
}
#endif // TEGLALAP_H
teglalap.cpp
#include "alakzat.h"
#include "teglalap.h"
namespace bme {
Teglalap::Teglalap(double x, double y, double magassag, double szelesseg)
: Alakzat(x, y), magassag(magassag), szelesseg(szelesseg) {
}
double Teglalap::terulet() const {
return magassag * szelesseg;
}
double Teglalap::kerulet() const {
return 2 * (magassag + szelesseg);
}
}
kor.h
#ifndef KOR_H
#define KOR_H
#include "alakzat.h"
namespace bme {
class Kor : public Alakzat {
private:
double sugar;
public:
Kor(double x, double y, double sugar);
double terulet() const override;
double kerulet() const override;
};
}
#endif // KOR_H
kor.cpp
#define _USE_MATH_DEFINES
#include "kor.h"
#include "alakzat.h"
#include <cmath>
namespace bme {
Kor::Kor(double x, double y, double sugar) : Alakzat(x, y), sugar(sugar) {}
double Kor::terulet() const {
return M_PI * sugar * sugar;
}
double Kor::kerulet() const {
return 2 * M_PI * sugar;
}
}
main.cpp
#include <iostream>
#include <vector>
#include "alakzat.h"
#include "teglalap.h"
#include "kor.h"
using namespace std;
using namespace bme;
int main() {
// Tároló különböző síkidomok számára
vector<Alakzat*> alakzatok;
alakzatok.push_back(new Teglalap(0, 0, 5, 10));
alakzatok.push_back(new Kor(2, 3, 4));
for (size_t i = 0; i < alakzatok.size(); ++i) {
cout << "Pozicio: " << (*alakzatok[i]).pozicio() << "\n";
cout << "Terulet: " << (*alakzatok[i]).terulet() << "\n";
cout << "Kerulet: " << (*alakzatok[i]).kerulet() << "\n\n";
}
for (size_t i = 0; i < alakzatok.size(); ++i) {
delete alakzatok[i];
}
return 0;
}
4. feladat.
Készítsünk egy matematikai kivételek kezelésére szolgáló osztályt,
amely az std::exception leszármazottja.
Származtassunk ebből további, speciális hibák esetén (pl.
0-val való osztás, szinguláris objektummal végzett tilos művelet, nem megfelelő
dimenziókból származó hiba)
dobandó kivételeket.
Írjuk felül a what() tagfüggvényt, mely szövegesen leírja az adott hibát.
Írjuk át a korábban írt Rational osztályt, amely racionális
számokat tárol. Dobjunk kivételt, ha a konstruktorban a nevezőt
0-ra állítják, ha 0-val akarnak osztani, ill. ha a 0-nak akarják a
reciprokát venni.
Használjuk a fent készített megfelelő kivételosztályt.
Megoldás:
mathexcept.h
#ifndef MATHEXCEPT_H
#define MATHEXCEPT_H
#include <exception>
using namespace std;
namespace bme {
class MathException : public exception {
public:
MathException() {}
const char* what() const noexcept override;
};
class DivByZeroExcept : public MathException {
public:
DivByZeroExcept() {}
const char* what() const noexcept override;
};
class DimensionExcept : public MathException {
public:
DimensionExcept() {}
const char* what() const noexcept override;
};
class SingularityExcept : public MathException {
public:
SingularityExcept() {}
const char* what() const noexcept override;
};
}
#endif
mathexcept.cpp
#include "mathexcept.h"
const char* bme::MathException::what() const noexcept {
return "ERROR: Mathematical error.";
}
const char* bme::DivByZeroExcept::what() const noexcept {
return "ERROR: Division by zero.";
}
const char* bme::DimensionExcept::what() const noexcept {
return "ERROR: Invalid dimensions.";
}
const char* bme::SingularityExcept::what() const noexcept
{
return "ERROR: Invalid operation on a singular object.";
}
rational.h
#ifndef RATIONAL_H
#define RATIONAL_H
#include <iostream>
using namespace std;
namespace bme {
class Rational {
private:
int numerator;
int denominator;
public:
Rational();
Rational(int num, int denom);
int getNumerator() const;
int getDenominator() const;
Rational operator+(const Rational&) const;
Rational operator-(const Rational&) const;
Rational operator*(const Rational&) const;
Rational operator/(const Rational&) const;
bool operator==(const Rational&) const;
bool operator!=(const Rational&) const;
Rational reciprocal() const;
friend ostream& operator<<(ostream& os, const Rational& r);
};
ostream& operator<<(ostream& os, const Rational& r);
}
#endif
rational.cpp
#include "rational.h"
#include <iostream>
#include "mathexcept.h"
using namespace std;
namespace bme {
Rational::Rational() {
numerator = 0;
denominator = 1;
}
Rational::Rational(int num, int denom) {
if (denom == 0) {
throw DivByZeroExcept(); // Nevező nem lehet 0
}
numerator = num;
denominator = denom;
}
int Rational::getNumerator() const {
return numerator;
}
int Rational::getDenominator() const {
return denominator;
}
Rational Rational::operator+(const Rational& other) const {
int commonDenom = denominator * other.denominator;
int newNumerator = numerator * other.denominator + other.numerator * denominator;
return Rational(newNumerator, commonDenom);
}
Rational Rational::operator-(const Rational& other) const {
int commonDenom = denominator * other.denominator;
int newNumerator = numerator * other.denominator - other.numerator * denominator;
return Rational(newNumerator, commonDenom);
}
Rational Rational::operator*(const Rational& other) const {
int newNumerator = numerator * other.numerator;
int newDenominator = denominator * other.denominator;
return Rational(newNumerator, newDenominator);
}
Rational Rational::operator/(const Rational& other) const {
if (other.numerator == 0) {
throw DivByZeroExcept(); // 0-val való osztás
}
int newNumerator = numerator * other.denominator;
int newDenominator = denominator * other.numerator;
return Rational(newNumerator, newDenominator);
}
bool Rational::operator==(const Rational& other) const {
return numerator * other.denominator == denominator * other.numerator;
}
bool Rational::operator!=(const Rational& other) const {
return !(*this == other);
}
Rational Rational::reciprocal() const {
if (numerator == 0) {
throw DivByZeroExcept(); // 0 reciprokának vétele
}
return Rational(denominator, numerator);
}
ostream& operator<<(ostream& os, const Rational& r) {
os << "(" << r.numerator << "/" << r.denominator << ")";
return os;
}
}
Egy teszt:
main.cpp
#include "rational.h"
#include "mathexcept.h"
#include <iostream>
using namespace std;
using namespace bme;
int main() {
try {
// Teszt: helyes racionális szám létrehozása
Rational r1(3, 4);
cout << "Rational r1: " << r1 << endl;
// Teszt: helytelen nevező (0)
Rational r2(1, 0);
}
catch (const MathException& e) {
cerr << e.what() << endl;
}
try {
// Teszt: osztás 0-val
Rational r3(1, 2);
Rational r4(0, 1);
Rational result = r3 / r4;
cout << "Result of division: " << result << endl;
}
catch (const MathException& e) {
cerr << e.what() << endl;
}
try {
// Teszt: 0 reciprokának vétele
Rational r5(0, 1);
Rational reciprocal = r5.reciprocal();
cout << "Reciprocal: " << reciprocal << endl;
}
catch (const MathException& e) {
cerr << e.what() << endl;
}
try {
// Teszt: helyes műveletek
Rational r6(1, 3);
Rational r7(2, 5);
Rational sum = r6 + r7;
Rational diff = r6 - r7;
Rational prod = r6 * r7;
Rational quot = r6 / r7;
cout << "Sum: " << sum << endl;
cout << "Difference: " << diff << endl;
cout << "Product: " << prod << endl;
cout << "Quotient: " << quot << endl;
}
catch (const MathException& e) {
cerr << e.what() << endl;
}
return 0;
}
5. feladat.
Írjunk
MxN-es mátrixokat reprezentáló template osztályt
(ahol a template paraméter az elemek típusa).
Írjunk konstruktort, ami paraméterként a mátrix méreteit kapja meg.
Az elemhozzáférést megvalósító operátor ill. tagfüggvény
implementációjában helytelen indexek esetén dobjunk kivételt.
A mátrixhoz lehessen hozzáadni, belőle kivonni más MxN-es-es mátrixokat,
valamint más mátrixszal is össze lehessen szorozni, amennyiben
a dimenziók nem megfelelőek a dobjunk kivételt.
Írjunk függvényt, amely négyzetes mátrix esetén kiszámolja a mátrix inverzét, 0 determináns
esetén dobjunk kivételt (elég 2x2-es mátrix esetén megvalósítani).
A kivételkezeléshez használjuk az előző feladatban készített kivételosztályokat.
Megoldás:
matrix2.hpp
#ifndef MATRIX2_HPP
#define MATRIX2_HPP
#include "mathexcept.h"
#include <stdexcept>
#include <iostream>
#include <vector>
using namespace std;
namespace bme {
template <typename T>
class Matrix2 {
private:
size_t rows, cols;
vector<vector<T>> data;
public:
Matrix2(size_t m, size_t n) : rows(m), cols(n), data(m, vector<T>(n, T())) {}
T& operator()(size_t i, size_t j) {
if (i >= rows || j >= cols) {
throw out_of_range("Index out of bounds!");
}
return data[i][j];
}
const T& operator()(size_t i, size_t j) const {
if (i >= rows || j >= cols) {
throw out_of_range("Index out of bounds!");
}
return data[i][j];
}
Matrix2<T> operator+(const Matrix2<T>& other) const {
if (rows != other.rows || cols != other.cols) {
throw DimensionExcept();
}
Matrix2<T> result(rows, cols);
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < cols; ++j) {
result(i, j) = data[i][j] + other(i, j);
}
}
return result;
}
Matrix2<T> operator-(const Matrix2<T>& other) const {
if (rows != other.rows || cols != other.cols) {
throw DimensionExcept();
}
Matrix2<T> result(rows, cols);
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < cols; ++j) {
result(i, j) = data[i][j] - other(i, j);
}
}
return result;
}
Matrix2<T> operator*(const Matrix2<T>& other) const {
if (cols != other.rows) {
throw DimensionExcept();
}
Matrix2<T> result(rows, other.cols);
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < other.cols; ++j) {
for (size_t k = 0; k < cols; ++k) {
result(i, j) += data[i][k] * other(k, j);
}
}
}
return result;
}
Matrix2<T> inverse() const {
if (rows != 2 || cols != 2) {
throw DimensionExcept();
}
T det = data[0][0] * data[1][1] - data[0][1] * data[1][0];
if (det == T(0)) {
throw SingularityExcept();
}
Matrix2<T> result(2, 2);
result(0, 0) = data[1][1] / det;
result(0, 1) = -data[0][1] / det;
result(1, 0) = -data[1][0] / det;
result(1, 1) = data[0][0] / det;
return result;
}
void print() const {
for (size_t i = 0; i < rows; ++i) {
for (size_t j = 0; j < cols; ++j) {
cout << data[i][j] << " ";
}
cout << "\n";
}
}
};
}
#endif
Egy teszt:
main.cpp
#include "matrix2.hpp"
#include "mathexcept.h"
#include <iostream>
using namespace bme;
int main() {
try {
Matrix2<double> mat1(2, 2);
mat1(0, 0) = 4; mat1(0, 1) = 12;
mat1(1, 0) = 2; mat1(1, 1) = 6;
cout << "Matrix 1:\n";
mat1.print();
cout << "\nInverse of Matrix 1:\n";
Matrix2<double> inv = mat1.inverse();
inv.print();
}
catch (const MathException& e) {
cerr << e.what() << "\n";
}
try {
Matrix2<double> mat1(2, 2);
mat1(0, 0) = 4; mat1(0, 1) = 12;
mat1(1, 0) = 2; mat1(1, 1) = 6;
cout << "Matrix 1:\n";
mat1.print();
Matrix2<double> mat2(2, 1);
mat2(0, 0) = 1; //mat2(0, 1) = 0;
mat2(1, 0) = 0; //mat2(1, 1) = 1;
cout << "Matrix 2:\n";
mat2.print();
cout << "\nSum of Matrix 1 and Matrix 2:\n";
Matrix2<double> sum = mat1 + mat2;
sum.print();
}
catch (const MathException& e) {
cerr << e.what() << "\n";
}
return 0;
}