compiler calls inherited class abstract
-
Hi,
I need to write a baseclass Algebra. Elements of an algebra can be added, multiplied, multiplied with a scalar ... I stuck to only multiplying and adding them.
Furthermore I need to write 2 specific classes (one for real numbers, one for 2x2 matrices) that inherit the baseclass. As you my have noticed, I am not trying to achieve anything with this code, but to learn about baseclasses.The Problem is, that my compiler claims, that my inherited classes are baseclasses. I assume that means that I am doing something wrong with the overwriting of the methods?
I spend quite some time looking for an answer and found loads of stuff, but still didn't manage to get a solution. What am I doing wrong?
Here is my Code (I post only the .h file as I assume the error is in there)
//include guard #ifndef __algebra_definded__ #define __algebra_definded__ #include <iostream> #include <vector> using namespace std; class Algebra{ private: public: Algebra(){}; virtual Algebra operator+(const Algebra &A)=0; //addition virtual Algebra operator*(const Algebra &A)=0; //multiplikation }; class Real: public Algebra{ private: double val; public: Real(){}; Real(double param); Real operator+(Real &R); Real operator*(Real &R); void print(); }; class Matrix: public Algebra{ private: vector<Real> elements; public: Matrix(){}; Matrix(Real e11,Real e12,Real e21,Real e22); Matrix operator+(Matrix &M); Matrix operator*(Matrix &M); void print(); }; #endifThanks a lot for your help!
If you need the rest of the code, I can of course post it!
Greetings
-
You cannot create an object of an abstract class. That is also true for returning it from a function. Thus, the operators in Algebra need to return a pointer or reference to an algebra.
The operators in Real and Matrix do not override the base functions as their parameters are different. They may return more specialized pointers or references (i.e. references to Real or Matrix) but they must take an Algebra as an parameter. BTW: Returning more specialized types is called covariant return types, you may want to look this up.
Thus, you get:class Algebra{ private: public: Algebra(){}; virtual Algebra& operator+(const Algebra &A)=0; //addition virtual Algebra& operator*(const Algebra &A)=0; //multiplikation }; class Real: public Algebra{ private: double val; public: Real(){}; Real(double param); Real& operator+(const Algebra &R); Real& operator*(const Algebra &R); void print(); }; class Matrix: public Algebra{ private: vector<Real> elements; public: Matrix(){}; Matrix(Real e11,Real e12,Real e21,Real e22); Matrix& operator+(const Algebra &M); Matrix& operator*(const Algebra &M); void print(); };As you can see, this is now totally useless
because it allows multiplication of Reals with any Algebra. This is because usage of inheritance and virtual functions is not appropriate in this case: You are breaking Liskov's substitution principle. This is important, you may want to look this up, too.You should reconsider the names of your classes: In mathematics real numbers and matrices form an algebra, but a real number a matrix themselves do not. They are just elements of an algebra. Also, an algebra does not have a multiplication or addition with other algebras but rather it defines an addition and multiplication of its elements with each other.
P.S.: Do not use
using namespacein header files. Doing so averts the whole use of namespaces. You do not even use anything fromstdin your header nor anything from the included headeriostream.
Also: what use is an empty constructor?
-
Hi Sepp,
thanks for the very quick and friendly reply. Your answer helped me a lot!
You are of course right saying that a single Real or Matrix doesn't form an algebra.
I tried to fix this by having the basisclass defined on a template. The classes inheriting will then specify the datatype and implement the operations + and * of the given Datatype (here: Real).However in order to implement the operations I need the operator to be called on the object Real, not realAlgebra, as RealAlgebra has no member "double val". I tried to fix this with defining the functions as "friend". However I had to find out, that such functions cannot be made virtual.
I know it is silly to define the + or * operation of a class in a different class, but that is (if I understood the task correctly) what I am supposed to do...
Does anyone have an idea how I can get the + and * to work?
Thanks in advance again!//include guard #ifndef __algebra_definded__ #define __algebra_definded__ class Real{ public: double val; Real(double param); void print(); }; //template template <typename Type> class Algebra{ public: virtual Type operator+(const Type &)=0; //addition virtual Type operator*(const Type &)=0; //multiplikation }; class RealAlgebra: public Algebra<Real>{ public: friend Real operator+(const Real &); friend Real operator*(const Real &); }; #endifPS: Style advise is always welcome as well!
Thanks a lot!
-
henn schrieb:
I tried to fix this with defining the functions as "friend".
Thats actually quite strange, isn't it?
friends are closer than family?
One tip: Try to (publicly) typedef'doubleinReal, cuz you may need to know the floating-point type used in it.if I understood the task correctly
...what you obviously didn't.. but excuse my english, in fact this is a german forum and i'm not used to that :D, probably i missunderstood your problem..
Edit: To that realAlgebra thing: Don't you think it's pointless? Because it actually is syntactically incorrect (don't you notice that you injure the ODR?).
-
You can do something like this:
template <typename ElementType> class HasAlgebra { public: const ElementType operator+(ElementType const& rhs) { return static_cast<ElementType*>(this)->add(rhs); } }; class Real : public HasAlgebra<Real> { private: double value; public: explicit Real(double value): value(value) {} const Real add(const Real& rhs) { return Real(value + rhs.value); } }; class Matrix : public HasAlgebra<Matrix> { private: double value; // I will not implement a whole matrix class. This is just a demonstration public: explicit Matrix(double value): value(value) {} const Matrix add(const Matrix& rhs) { return Matrix(value + rhs.value); } }; int main() { Real real_a(1), real_b(2); real_a + real_b; // Compiles Matrix mat_a(1), mat_b(2); mat_a + mat_b; // Compiles real_a + mat_b; // Does not compile }Maybe choose some better names for the classes. I did not feel creative, these do not really fit.
This is called the curiously recurring template pattern.
-
Hi,
thanks a lot for your time and effort!
Helped a lot!
Greetings