Dziedziczenie - problem z linkowaniem (?)

0

Pisze program o matrixach, vectorach, scalarach... =P
I program działa i kompilował się poprawnie dopóki nie zabrałem sie za mnożenie. Mnożenie to postanowiłem zrealizować tworząc wirtualną klase Math i bazując na niej przeładowywać operator mnożenia. Math.h wygląda tak:

//math.h
#ifndef MATH_H
#define MATH_H

#include "scalar.h"
#include "vector.h"
#include "matrix.h"

class Math {
public:
    virtual Math& operator*(Math& rv) = 0;
    virtual Math& multiply(Scalar& s) = 0;
    virtual Math& multiply(Vector& v) = 0;
    virtual Math& multiply(Matrix& m) = 0;
    virtual ~Math() {}
};

#endif //MATH_H

Teraz chciałem aby klasy Scalar, Vector, Matrix dziedziczyły po Math. Ich deklaracje wyglądają tak:

//Scalar.h
#ifndef SCALAR_H
#define SCALAR_H

#include "math.h"
#include <iostream>

class Scalar : public Math {
    int value;
public:
        //constructor
    Scalar(int sz = 0) : value(sz) {}
        //destructor
    ~Scalar() {}
        //set value of value
    void setValue(int val);
        //overloading operator= for int
    Scalar& operator=(const int& i);
        //overloading operator= for Scalar
    Scalar& operator=(const Scalar& s);
        //overloading operator+
    Scalar& operator+(const Scalar& s) const;
        //overloading opeartor-
    Scalar& operator-(const Scalar& s) const;
        //overloading operator<<
    friend std::ostream& operator<<(std::ostream& os, const Scalar& s);
        //overloading in operator>>
    friend std::istream& operator>>(std::istream& is, Scalar& s);
};

#endif //SCALAR_H      
// Vector.h
#ifndef VECTOR_H
#define VECTOR_H

#include "math.h"
#include <iostream>

class Vector : public Math{
    int size;
    Scalar *scalars;
public:
        //default constructor
    Vector() : size(0), scalars(0) {}
        //constructor
    Vector(int sz);
        //copy-constructor
    Vector(const Vector& v);
        //destructor
    ~Vector();
        //return the size of Vector
    int getSize() const;
        //set vector size
    void setSize(int sz);
        //overloading bracket operator[]
    Scalar& operator[](int x) const;
        //overloading operator=
    Vector& operator=(const Vector& v);
        //overloading operator+
    Vector& operator+(const Vector& v) const;
        //overloading opeartor-
    Vector& operator-(const Vector& v) const;
        //overloading operator<<
    friend std::ostream& operator<<(std::ostream& os, const Vector& v);
        //overloading in operator>>
    friend std::istream& operator>>(std::istream& is, Vector& v);
};

#endif //VECTOR_H
// Matrix.h
#ifndef MATRIX_H
#define MATRIX_H

#include "math.h"
#include <iostream>

class Matrix : public Math {
    int size;
    Vector *vectors;
public:
        //default constructor
    Matrix() : size(0), vectors(0) {}
        //constructor
    Matrix(int sz);
        //copy-constructor
    Matrix(const Matrix& m);
        //destructor
    ~Matrix();
        //return the size of Matrix
    int getSize() const;
        //overloading operator[]
    Vector& operator[](int x) const;
        //overloading operator=
    Matrix& operator=(const Matrix& m);
        //overloading operator+
    Matrix& operator+(const Matrix& m) const;
        //overloading operator-
    Matrix& operator-(const Matrix& m) const;
        //overloading operator<<
    friend std::ostream& operator<<(std::ostream& os, const Matrix& m);
        //overloading in operator>>
    friend std::istream& operator>>(std::istream& is, Matrix& m);
};

#endif //MATRIX_H

A teraz co wypluwa g++

g++ -Wall -pedantic -O0 -g -c scalar.cpp
In file included from math.h:6,
                 from scalar.h:5,
                 from scalar.cpp:1:
vector.h:8: error: expected class-name before '{' token
vector.h:10: error: ISO C++ forbids declaration of 'Scalar' with no type
vector.h:10: error: expected ';' before '*' token
vector.h:25: error: ISO C++ forbids declaration of 'Scalar' with no type
vector.h:25: error: expected ';' before '&' token
vector.h: In constructor 'Vector::Vector()':
vector.h:13: error: class 'Vector' does not have any field named 'scalars'
In file included from math.h:7,
                 from scalar.h:5,
                 from scalar.cpp:1:
matrix.h: At global scope:
matrix.h:8: error: expected class-name before '{' token
In file included from scalar.h:5,
                 from scalar.cpp:1:
math.h:12: error: 'multiply' declared as a 'virtual' field
math.h:12: error: expected ';' before '(' token
scalar.cpp: In member function 'virtual Math& Scalar::operator*(Math&)':
scalar.cpp:33: error: no matching function for call to 'Math::multiply(Scalar&)'
math.h:13: note: candidates are: virtual Math& Math::multiply(Vector&)
math.h:14: note:                 virtual Math& Math::multiply(Matrix&)
scalar.cpp: At global scope:
scalar.cpp:42: error: no 'Math& Scalar::mulitply(Vector&)' member function declared in class 'Scalar'
matrix.h: In member function 'virtual Math& Scalar::multiply(Matrix&)':
matrix.h:9: error: 'int Matrix::size' is private
scalar.cpp:51: error: within this context
matrix.h:9: error: 'int Matrix::size' is private
scalar.cpp:52: error: within this context
matrix.h:9: error: 'int Matrix::size' is private
scalar.cpp:53: error: within this context
matrix.h:10: error: 'Vector* Matrix::vectors' is private
scalar.cpp:54: error: within this context
matrix.h:10: error: 'Vector* Matrix::vectors' is private
scalar.cpp:54: error: within this context
scalar.cpp:54: error: no match for 'operator*' in '*(m->Matrix::vectors + ((long unsigned int)(((long unsigned int)i) * 4ul))) * ((Scalar*)this)->Scalar::value'
scalar.cpp:55: error: invalid initialization of reference of type 'Math&' from expression of type 'Matrix'
make: *** [scalar.o] Error 1

Z takiego tłumu linijek wnioskuję, że cos sie nie zgadza z linkowaniem (chyba w ogóle nie widzi klasy Math), ale so far nie wpadłem na to co to może być.
Jak ktoś ma pomysł... bedę bardzo wdzięczny :D
W załączniku zamieszczam cały kod źródłowy razem z Makefilem

0

Hmm, na mój gust nie pasuje to:

//math.h
#ifndef MATH_H
#define MATH_H
 
#include "scalar.h" // <- !
#include "vector.h" // <- !
#include "matrix.h" // <- !
class Math {
//Scalar.h
#ifndef SCALAR_H
#define SCALAR_H
 
#include "math.h" // <- !
#include <iostream>

class Scalar : public Math {
// Vector.h
#ifndef VECTOR_H
#define VECTOR_H
 
#include "math.h" // <- !
#include <iostream>
 
class Vector : public Math{
0

w sumie racja, takie zapętlające się...
ale którego sie pozbyć...?

0

@_13th_Dragon:
<aaa>
Będziemy sie bawić w kotka i myszkę? =P
Widzę, że chodzi o problem z headeremi, ale nie wiem jak je inaczej (poprawnie) ułożyć, żeby działało a jednoczenie sie dobrze łączyło...
Więc, if you please, można prosić o explicit hint :D

0
  1. Nazywanie plików nagłówkowych tak samo jak te z biblioteki standardowej to terroryzm
  2. Tak samo nazywanie sobie tak klas...
  3. Lekcja na dziś: deklaracje zapowiadające. Bo takie Math nie musi znać definicji Scalar. Wystarczy że będzie poinformowane że Scalar to jakis typ.
0

Math nie potrzebuje nic wiedzieć o wektorach, skalarach.
Czemu stosujesz polimorfizm, skoro go nie rozumiesz?

0

hmmm...
czyli po usunięcu '#includów' z math.h powinno chodzić?
nie chodzi!
nawet pozwoliłem sobie na tymczasowe rozwiązanie pozbywające sie problemu linkowania:
wrzuciłem wszyskie deklaracje klass do jednego pliku "lib.h" a do plików scalar.cpp, vector.cpp, matrix.cpp dodalem '#include "lib.h"'. Powinno działać?
nie działa!
za to wywala coś takiego:

g++ -Wall -pedantic -O0 -g -c scalar.cpp
In file included from scalar.cpp:1:
lib.h:10: error: 'multiply' declared as a 'virtual' field
lib.h:10: error: expected ';' before '(' token
lib.h:11: error: 'multiply' declared as a 'virtual' field
lib.h:11: error: expected ';' before '(' token
lib.h:12: error: 'multiply' declared as a 'virtual' field
lib.h:12: error: expected ';' before '(' token
lib.h:36: error: 'multiply' declared as a 'virtual' field
lib.h:36: error: expected ';' before '(' token
lib.h:37: error: 'multiply' declared as a 'virtual' field
lib.h:37: error: expected ';' before '(' token
scalar.cpp: In member function 'virtual Math& Scalar::operator*(Math&)':
scalar.cpp:33: error: 'class Math' has no member named 'multiply'
scalar.cpp: At global scope:
scalar.cpp:42: error: no 'Math& Scalar::mulitply(Vector&)' member function declared in class 'Scalar'
scalar.cpp:50: error: prototype for 'Math& Scalar::multiply(Matrix&)' does not match any in class 'Scalar'
scalar.cpp:36: error: candidate is: virtual Math& Scalar::multiply(Scalar&)
make: *** [scalar.o] Error 1

Wiec być może nie rozumiem do konca polimorfizmu (kiedyś rozumiałem, ale rok kodowania w C potrafi nadpisać parę cennych informacji).
Załączam "lib.h"

0

Dobra, może inaczej. Math nie potrzebuje całej deklaracji klas Scalar, Vector. Musi wiedzieć tylko o ich istnieniu.
Można to zapewnić tak:
class Vector;
class Scalar;
class Matrix;

A jeżeli nie rozumiesz polimorfizmu to z niego nie korzystaj. Nie możesz tego zaprojektować inaczej? Klasa Scalar? Naprawdę warto np. zwiększać rozmiar samych obiektów żeby zyskać... no właśnie, co?

0

ok, dzięki
teraz sie douczam (zgonie z sugestią) i jak to naprawię dam znać ;)
btw: używam polimorfizmu bo potem chce użyć metod multiply() do przeładowania operatora*=
W ten sposób chyba nie bede musiał pisac mnożenia dwa razy (?)

0

Napisałeś dodatkową klasę (interfejs) Math, utworzyłeś dla niej osobny plik. Potem w każdej klasie zaimplementowałeś te metody łącznie z kolejną deklaracją tych metod w obrębie tych klas pochodnych. Obciążyłeś same obiekty dodatkowymi bajtami informacji, zamknąłeś liczbę w strukturze i dopisałeś do niej akcesory. I chcesz powiedzieć, że to wszystko po to, żeby nie pisać 2 razy tych samych funkcji?

Tak naprawdę to nawet nie 2 razy, bo przecież mając operator*(Matrix m, Vector v) ; Można napisać drugi:
operator*(Vector v, Matrix m) {return m*v;}

Jest tam jeszcze wiele innych błędów. Polimorfizm to ostateczność.

0

w sumie masz rację =)
po cześci chciałem się pobawić =P
ale chyba jednak zrezygnuję z tego polimorfizmu i klepnę to "po staremu", na polimorfizm przyjdzie kolej innym razem (a te błedy pewnie wynikają z tego żę na dziedziczenie zdecydowalem sie w połowie programu, przez to jest to takie nienaturalne... a pisac od nowa mi sie ani nie chciało, ani nie chce =P)
Podsumowując: dzięki wam z podpowiedzi (może trochę za bardzo czuję sie zbesztany, ale to przeżyję =P) i wracam do starej fomy. A to że zapomniałem o deklaracjach klas przez definicją Math (cóz... głupota + to jednak jest mój pierwszy program w Cpp do roku)
Dzięki once more :D

0

przerwę jednak tą błogą ciszę w tym wątku... bo mam problem... z '#includami'
w scalar.h musze zamieścić np taką funkcję

Vector& operator*(const Vector& v) const;

czyli musze też dać nagłówek '#include "vector.h"'
z koleii w vector.h używam '#include "scalar.h"'
<zonk>
da sie to jakoś odkręcić... i czy to nie jest dobre miejsce na użycie dziedziczenia (??)

0

A czemu uważasz ze musisz includować ten vector.h do tej deklaracji? Na moje oko wystarczy ci deklaracja zapowiadająca...

0

bo chce sobie klepnąc cos w ten deseń:

Vector& operator*(const Scalar& s, const Vector& v) const {
	return v * s;
}

gdzie w vector.h bedzie napisana metoda mnożąca vector * scalar
a nawet gdybym zrezygnował z tego ułatwienia, to i tam potrzebuję miec dostęp do metod Vectora takich jak vector.getSize()
wiec, na moje oko, musze miec dostęp do klasy Vector...
proszę, poprawcie mnie i powiedzcie jak to zrobić inaczej, jeśli się myle

0

No jeśli tak chcesz zrobić to masz problem. Z reguły oddziela się w takiej sytuacji implementację od deklaracji. Tzn w nagłówku masz tylko deklaracje. Oprócz tego masz pliki *.cpp z implementacjami metod.

0

tak też mam ;)
głupi jestem i tyle... jak zrobie w nagłówku 'class Vector;' a w pliku Scalar.cpp dołączam #include "vector.h"; #include "matrix.h" to zadziała?
damn

0

Operatory binarne można napisać na zewnątrz klas. Można powiedzieć, że mają charakter funkcji, a nie metod, więc jest to nawet uzasadnione.

1 użytkowników online, w tym zalogowanych: 0, gości: 1