Tworzę program, w którym są różne figury. Mam je wyświetlić na ekranie np. ich koordynaty itp. Jest dużo dziedziczenia. Figura to klasa bazowa. Okrag, prostokat,trojkat i odcinek dziedziczy po klasie Figura. Punkt to klasa niezależna.
kompiluj programy w ten sposób (potem stworzę makefile)
g++ -c odcinek.cpp -Wall
g++ -c trojkat.cpp -Wall
g++ -c prostokat.cpp -Wall
g++ -c okrag.cpp -Wall
g++ -o figury.x figury.o trojkat.o prostokat.o okrag.o odcinek.o -Wall
Używam cppcheck do sprawdzenia kazdego pliku .cpp
Oto mój kod:
punkt.h
// Plik punkt.h
// Klasa Punkt do reprezentowania punktu na płaszczyźnie
#ifndef PUNKT_H
#define PUNKT_H
#include <iostream>
#include <cstdlib>
namespace MojeFigury {
class Punkt {
double x, y; // wspolrzedne x i y
public:
// Konstruktor
Punkt(double a = 0, double b = 0): x(a), y(b) {}
// Funkcja zwracająca współrzedną x
double dajX() const{ return x; }
// Funkcja zwracająca współrzedną y
double dajY() const{ return y; }
// Funkcja do przesuwania punktu na płaszczyźnie
// o wektor (dx,dy)
void przesun(double dx, double dy);
// Funkcja do skalowania punktu -pusta
void skaluj(double s) {}
// Przeładowanie operatorów relacyjnych: == i !=
friend bool operator==(const Punkt&, const Punkt&);
friend bool operator!=(const Punkt&, const Punkt&);
// Przeładowanie operatorów strumieniowych: << i >>
friend std::ostream& operator<<(std::ostream&,const Punkt&);
friend std::istream& operator>>(std::istream&, Punkt&);
}; // classPunkt
//-----------Funkcje inline--------------------------
// Funkcja do przesuwania punktu na płaszczyźnie
// o wektor (dx,dy)
inline void Punkt::przesun(double dx, double dy) {
x += dx;
y += dy;
}
//===== Przeładowanie operatorów relacyjnych =========
inline bool operator==(const Punkt& a, const Punkt& b)
{
return (a.x== b.x) && (a.y== b.y);
}
inline bool operator!=(const Punkt& a, const Punkt& b)
{
return (a.x!= b.x) || (a.y!= b.y);
}
//===== Przeładowanie operatorów strumieniowych =======
inline std::ostream& operator<<(std::ostream& wy, const Punkt& p)
{
wy << '(' << p.x<< ',' << p.y<< ')';
return wy;
} //operator<<
inline std::istream& operator>>(std::istream& we, Punkt& p)
{
char c;
we >> c;
if (c != '(') {
std::cerr<< "Operator >>: Nieprawidlowyformat punktu!"
<< std::endl;
std::exit(1);
}
we >> p.x;
we >> c;
if (c != ',') {
std::cerr << "Operator >>: Nieprawidlowyformat punktu!"
<< std::endl;
std::exit(2);
}
we >> p.y;
we >> c;
if (c != ')') {
std::cerr << "Operator >>: Nieprawidlowyformat punktu!"
<< std::endl;
std::exit(3);
}
return we;
} // operator >>
} // namespace MojeFigury
#endif // PUNKT_H
figura.h
// Plikfigura.h
// Klasa abstrakcyjna Figura dla figur geometrycznych
#include <string>
#include <iostream>
#ifndef FIGURA_H
#define FIGURA_H
using namespace std;
namespace MojeFigury {
class Figura { // Klasa abstrakcyjna Figura
public:
// Czysto wirtualny destruktor
virtual~Figura() = 0;
// Funkcja czysto wirtualna do rysowania figur
virtual void rysuj(void) = 0;
// Funkcja czysto wirtualna do przesuwania figur
virtual void przesun(double, double) = 0;
// Funkcja czysto wirtualna do skalowania figur
virtual void skaluj(double) = 0;
// Zagnieżdżonaklasa do obsługi wyjątków dla funkcji skaluj
class ZlaSkala{
double s; // skala
string gdzie; // miejsce zgłoszenia wyjątku: klasa
public:
// Konstruktor
ZlaSkala(double x=0,std::string opis=""): s(x),gdzie(opis){}
// Zwróć skalę
float dajSkale() const{ return s; }
// Komunikat
void Komunikat() const{
std::cerr<< "\nWyjatek w funkcji skaluj dla klasy: "
<< gdzie << ": zla skala s = " << s << std::endl;
}
}; // classZlaSkala
}; // classFigur
// Definicja czysto wirtualnego destruktora (tu: pusty).
//Obowiązkowa!!!
//-> Na wypadek gdyby jakaś klasa pochodna
// nie zdefiniowała własnego destruktora!
// (Wtedy stałaby się klasą abstrakcyjną,
// bo destruktor zadeklarowaliśmy jako
// czysto wirtualny.)
inline Figura::~Figura() {}
} // namespace MojeFigury
#endif // FIGURA_H
odcinek.h
// Plik odcinek.h
// Definicja klasy Odcinek do reprezentowania odcinka
// Klasa Odcinek dziedziczy po klasie abstrakcyjnej Figura
#ifndef ODCINEK_H
#define ODCINEK_H
#include "figura.h" // Plik nagłówkowy dla klasy Figura
#include "punkt.h" // Plik nagłówkowy dla klasy Punkt
namespace MojeFigury {
// Klasa Odcinek – dziedziczy po klasie Figura
class Odcinek: public Figura {
Punkt poczatek, koniec; // Punkty początkowy i końcowy
public:
//Konstruktor, w tym domyślny (przykładowy)
Odcinek(Punkt a = Punkt(0,1), Punkt b = Punkt(0,0));
// Funkcja do rysowania odcinka w oknie
void rysuj(void);
// Funkcja do przesuwania odcinka
void przesun(double, double);
// Funkcja do skalowania odcinka
void skaluj(double);
// Klasa do obsługi wyjątków
class ZleKonce {
Punkt p, k; // konce odcinka
public:
// Konstruktor
ZleKonce(Punkt a, Punkt b): p(a), k(b) {}
// Zwróć końce odcinka
void dajKonce(Punkt& a, Punkt& b) const
{ a = p; b = k; }
// Komunikat
void Komunikat() const
{
std::cerr<< "\n* Wyjatek: class Odcinek: poczatek"
<< p << " = koniec" << k << std::endl;
}
}; // class ZleKonce
}; // class Odcinek
// Definicja konstruktora
inline Odcinek::Odcinek(Punkt a, Punkt b) {
if (a != b) {
poczatek = a; koniec = b;
}
// Rzucanie wyjątku gdy złe końce,
// tzn. poczatek = koniec
else
throw Odcinek::ZleKonce(a, b);
}
} // namespaceMojeFigury
#endif
odcinek.cpp
// Plik odcinek.cpp
// Implementacja metod klasy Odcinek
#include "odcinek.h"
namespace MojeFigury {
// Funkcja do rysowania odcinka
void Odcinek::rysuj(){
std::cout << "Rysuje odcinek o poczatku P" << poczatek
<< " i koncu K" << koniec << std::endl;
}
// Funkcja do przesuwania odcinka o wektor (dx,dy)
void Odcinek::przesun(double dx, double dy) {
koniec.przesun(dx,dy);
poczatek.przesun(dx,dy);
}
// Funkcja do skalowania odcinka
void Odcinek::skaluj(double s) {
if(s <= 0) throw Figura::ZlaSkala(s, "Odcinek");
double x0 = poczatek.dajX();
double delx= koniec.dajX() -x0;
double y0 = poczatek.dajY();
double dely= koniec.dajY() -y0;
// Nowe współrzędne końca -po przeskalowaniu
double x = x0 + s*delx;
double y = y0 + s*dely;
koniec = Punkt(x,y);
}
} // namespace MojeFigury
Plik główny
// Plikfigura.h
// Klasa abstrakcyjna Figura dla figur geometrycznych
#include <string>
#include <iostream>
#include "figura.h" // Plik nagłówkowy dla klasy Figura
#include "punkt.h" // Plik nagłówkowy dla klasy Punkt
#include "odcinek.h" // Plik nagłówkowy dla klasy Figura
#include "trojkat.h" // Plik nagłówkowy dla klasy Punkt
#include "prostokat.h" // Plik nagłówkowy dla klasy Figura
#include "okrag.h" // Plik nagłówkowy dla klasy Punkt
using namespace std;
using namespace MojeFigury;
int main() {
try {
// deklaracje, definicje, instrukcje, wywołania funkcji, ...
} catch(Odcinek::ZleKonce& zk) {
// obsługa wyjątku dla konstruktora odcinka, np.
zk.Komunikat();
} catch(Trojkat::ZleWierzcholki& zw) {
// obsługa wyjątku dla konstruktora trójkąta
zw.Komunikat();
} catch(Prostokat::ZleBoki& zb) {
// obsługa wyjątku dla konstruktora prostokąta
zb.Komunikat();
} catch(Okrag::ZlyPromien& zp) {
// obsługa wyjątku dla konstruktora okręgu
zp.Komunikat();
} catch(Figura::ZlaSkala& zs) {
// obsługa wyjątku dla metody skaluj()
zs.Komunikat();
} catch(...) { // domyślna obsługa wyjątków
cerr << "Nieznany wyjątek" << endl;
exit(1);
}
Odcinek odc1(Punkt c = Punkt(0,1), Punkt d = Punkt(0,3));
odc1.rysuj();
return 0;
}
Wyskakuje mi w takim przypadku błąd przy g++ -c figury.cpp -Wall
figury.cpp: In function ‘int main()’:
figury.cpp:39:10: error: request for member ‘rysuj’ in ‘odc1’, which is of non-class type ‘MojeFigury::Odcinek(MojeFigury::Punkt, MojeFigury::Punkt)’
odc1.rysuj();
Natomiast gdy podaje obiekt bez parametrów wszystko jest super
Odcinek odc1;
odc1.rysuj();
, no ale chyba pasuje stworzyć jakiś odcinek z konkretnymi współrzędnymi.
Wiecie w czym może być problem?