Template Problems

For an assignment I have to write some code in only a header file to get practice with templates. Although I think I was able to get most of the coding correct I'm running into some errors that I just can't figure out and I was hoping you guys would be able to help.

The questions I'm having trouble with are the following:

5.Inherit from the Number class to create a new class named ComplexNumber.
This class will add an additional protected variable (for the imaginary
part). Add setImaginary and getImaginary functions to this class. These
functions will do the same thing as the getValue and setValue functions, but
for the imaginary part that only the ComplexNumber has.
Important concept: You can NOT override the getNumber and setNumber functions
to, for example, add an additional parameter to setNumber for the imaginary
component. This would change the function signature so you would just be
making a new function.

6.Override the to_string class of Number<T> in ComplexNumber to return a
string in the format x+yi (or x-yi), where x is the real component and y is the
imaginary component. Note that C++ will require you to be very explicit about
what component from the parent class is being accessed; calling getValue()
will fail but calling Number<T>::getValue() will compile.

7.Override the multiply operator so that multiplying two ComplexNumbers will
yield a ComplexNumber.

8.Override the multiply operator so that multiplying a Number and a
ComplexNumber will result in a ComplexNumber. Note that you will need to
override this more than once to cover the case where the Number is first and
where the Number is second. (Or you can use dynamic cast to check if a
reference to a number refers to a ComplexNumber, but this is more complicated)

9.Write a function named complexSum that accepts a reference to a
std::vector<Number<T>*>, where T is a template type. This function will use dynamic cast to check each
element to see if it is a ComplexNumber and will return the sum of the complex
components of all ComplexNumbers in the vector. The sum will be a template of
the ComplexNumber type.


My code is as follows, and it includes some code regarding earlier questions not mentioned here as well. But please let me know if you see any problems with it:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>
using namespace std;

#ifndef homework3_homework3_h
#define homework3_homework3_h


template <class T>
class Number //Defining Number class
{
protected:
    T n; //Data member n
public:
    T getValue() //getter function
    {return n;}
    
    void setValue(T tn) //setter function
    {n=tn;}
    
    virtual string toString() //virtual function to be overrided
    {
        return to_string(n);
    }
    
    Number operator*(Number &t) //operator overloading *
    {
        Number tn;
        tn.n=n*t.n;
        return tn; //return product
    }
};

template <typename T>
class ComplexNumber : public Number <T> //sub class of Number
    {
    T imag; //sub class properity imag
    
public:
    T getImaginary() //getter function
    {return imag;}
    
    void setImaginary(T im) //setter function
    {imag=im;}
    
    string toString() //overrided toString function
    {
        return to_string(this->n+imag);//return converted string function
    }
    
    ComplexNumber operator *(ComplexNumber ct) //overrided operator *
    {
        ComplexNumber c;
        c.n=this->n*ct.n; //product of real part
        c.imag=imag*ct.imag; //product of imaginary part
        return c; //return product number
    }

void complexSum(vector <Number<T>*> ref) //vector of numbers
{
    cout<<"\nSum of complext numbers : "<<ref.getValue()+ref.getImaginary();
}
};

#endif 
Last edited on
Also forgot to mention there is a test program that goes along with that if run with the header file, it will tell if the code is correct or not:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#include "number.h"
#include <iostream>

template <typename T>
bool testNumber(T value) {
    Number<T> num;
    num.setValue(value);
    if (num.getValue() != value) {
        std::cerr<<"Number's setValue/getValue fails with value "<<value<<'\n';
        return false;
    }
    if (std::to_string(value) != num.toString()) {
        std::cerr<<"Number's toString fails with value "<<value<<'\n';
        return false;
    }
    return true;
}

template <typename T>
bool testImaginary(T value, T i) {
    ComplexNumber<T> num;
    num.setValue(value);
    num.setImaginary(i);
    if (num.getValue() != value or num.getImaginary() != i) {
        std::cerr<<"ComplexNumber's get/setImaginary fails with value "<<value<<"+"<<i<<"i\n";
        return false;
    }
    return true;
}

template <typename T>
bool testImaginaryString(T value, T i) {
    ComplexNumber<T> num;
    num.setValue(value);
    num.setImaginary(i);
    std::string expected = std::to_string(value);
    if (0 <= i) {
        expected +=	"+";
    }
    expected += std::to_string(i) + "i";
    if (expected != num.toString()) {
        std::cerr<<"ComplexNumber's toString fails with value "<<expected<<"\n";
        return false;
    }
    return true;
}


template<typename T>
bool testMultiply(T avalue, T bvalue) {
    Number<T> a;
    Number<T> b;
    a.setValue(avalue);
    b.setValue(bvalue);
    Number<T> c = a*b;
    
    return (avalue*bvalue) == c.getValue();
}

template<typename T>
bool testComplexMultiply(T areal, T ai, T breal, T bi) {
    ComplexNumber<T> a;
    ComplexNumber<T> b;
    a.setValue(areal);
    a.setImaginary(ai);
    b.setValue(breal);
    b.setImaginary(bi);
    ComplexNumber<T> c = a*b;
    
    return (areal*breal - ai*bi) == c.getValue() and (areal*bi + ai*breal) == c.getImaginary();
}


template<typename T>
bool testMixedMultiply(T areal, T ai, T breal) {
    ComplexNumber<T> a;
    Number<T> b;
    a.setValue(areal);
    a.setImaginary(ai);
    b.setValue(breal);
    ComplexNumber<T> c = a*b;
    ComplexNumber<T> d = b*a;
    
    bool same = c.getValue() == d.getValue() and c.getImaginary() == d.getImaginary();
    bool correct = c.getValue() == (areal*breal) and c.getImaginary() == (breal*ai);
    return same and correct;
}

//Tired of typing this out
void passFail(bool success) {
    if (success) {
        std::cout<<"\tpassed!\n";
    }
    else {
        std::cout<<"\tfailed!\n";
    }
}

int main(int argc, char** argv) {
    //20% for the templated Number class with the function
    //getValue, setValue, and toString
    std::cout<<"Testing getValue, setValue, and toString:\n";
    std::cout<<"Testing Number<int> with value 3...\n";
    passFail(testNumber<int>(3));
    
    std::cout<<"Testing Number<double> with value 4.8...\n";
    passFail(testNumber<double>(4.8));

    
    //10% For overloading the multiply operator for Number
    std::cout<<"Testing operator* for Number:\n";
    std::cout<<"Testing Number<long int>...\n";
    passFail(testMultiply<long int>(3, 9));
    std::cout<<"Testing Number<double>...\n";
    passFail(testMultiply<double>(3.3, 9.8));

    //20% For Creating ComplexNumber by inheriting from Number.
    // Define member functions for getImaginary and setImaginary
    std::cout<<"Testing getImaginary and setImaginary:\n";
    std::cout<<"Testing ImaginaryNumber<int> with value 3-2i...\n";
    passFail(testImaginary<int>(3, -2));
    std::cout<<"Testing ImaginaryNumber<double> with value -2.1+0.1i...\n";
    passFail(testImaginary<double>(-2.1, 0.1));
    
    //10% Override the to_string class of Number<T> in
    // ComplexNumber to return a string in the format x+yi, where x
    // is the real component and y is the imaginary component.
    std::cout<<"Testing toString of ComplexNumber:\n";
    std::cout<<"Testing ImaginaryNumber<int> with value -2-8i...\n";
    passFail(testImaginaryString<int>(-2, -8));
    std::cout<<"Testing ImaginaryNumber<double> with value 2.1-0.1i...\n";
    passFail(testImaginaryString<double>(2.1, -0.1));

    //10% Override the multiply operator so that multiplying two
    // ComplexNumbers will yield a ComplexNumber.
    std::cout<<"Testing operator* for two ComplexNumbers:\n";
    std::cout<<"Testing ComplexNumber<char>...\n";
    passFail(testComplexMultiply<char>(4, 8, 3, -2));
    std::cout<<"Testing ComplexNumber<float>...\n";
    passFail(testComplexMultiply<float>(0.23, 3.5, -3.1, -2.22));
    
    
    //10% Override the multiply operator so that multiplying a
    // Number and a ComplexNumber will result in a ComplexNumber.
    std::cout<<"Testing operator* Number and ComplexNumber:\n";
    std::cout<<"Testing Number/ComplexNumber<int>...\n";
    passFail(testMixedMultiply<char>(4, 8, 3));
    std::cout<<"Testing Number/ComplexNumber<double>...\n";
    passFail(testMixedMultiply<float>(-4.1, 5, 15));

    //10% Write a function named complexSum that accepts a
    // reference to a std::vector<Number<T>*>, where T is a
    // template type.
    Number<int> a;
    a.setValue(3);
    Number<int> b;
    b.setValue(4);
    ComplexNumber<int> c;
    c.setValue(5);
    c.setImaginary(-1);
    Number<int> d;
    d.setValue(0);
    ComplexNumber<int> e;
    e.setValue(1);
    e.setImaginary(-2);
    Number<int> f;
    f.setValue(2);
    Number<int> g;
    g.setValue(3);
    ComplexNumber<int> h;
    h.setValue(4);
    h.setImaginary(-3);
    
    std::vector<Number<int>*> nums;
    nums.push_back(&a);
    nums.push_back(&b);
    
    std::cout<<"Testing complexSum\n";
   
    std::cout<<"Testing without any complex numbers...\n";
    ComplexNumber<int> intresult = complexSum(nums);
    passFail(intresult.getValue() == 7 and intresult.getImaginary() == 0);
    
    nums.push_back(&c);
    nums.push_back(&d);
    nums.push_back(&e);
    nums.push_back(&f);
    nums.push_back(&g);
    nums.push_back(&h);
    
    std::cout<<"Testing with ComplexNumber<int>...\n";
    intresult = complexSum(nums);
    passFail(intresult.getValue() == 22 and intresult.getImaginary() == -6);
    
    ComplexNumber<double> z;
    z.setValue(-3.1);
    z.setImaginary(3.2);
    std::vector<Number<double>*> doublenums;
    doublenums.push_back(&z);
    
    std::cout<<"Testing with ComplexNumber<double>...\n";
    ComplexNumber<double> doubleresult = complexSum(doublenums);
    passFail(doubleresult.getValue() == -3.1 and doubleresult.getImaginary() == 3.2);
    
    return 0;
}

And the errors?
sorry, thought i mentioned them but the errors are:


main.cpp:181:36: error: use of undeclared identifier 'complexSum'
ComplexNumber<int> intresult = complexSum(nums);


main.cpp:192:17: error: use of undeclared identifier 'complexSum'
intresult = complexSum(nums);


main.cpp:202:42: error: use of undeclared identifier 'complexSum'
ComplexNumber<double> doubleresult = complexSum(doublenums);


main.cpp:81:27: error: invalid operands to binary expression
('ComplexNumber<char>' and 'Number<char>')
ComplexNumber<T> c = a*b;


main.cpp:82:22: error: no viable conversion from 'Number<char>' to
'ComplexNumber<char>'
ComplexNumber<T> d = b*a;


main.cpp:81:27: error: invalid operands to binary expression
('ComplexNumber<float>' and 'Number<float>')
ComplexNumber<T> c = a*b;


main.cpp:82:22: error: no viable conversion from 'Number<float>' to
'ComplexNumber<float>'
ComplexNumber<T> d = b*a;


Seems like a lot of errors but i feel as though some of them can be fixed together
main.cpp:181:36: error: use of undeclared identifier 'complexSum'
ComplexNumber<int> intresult = complexSum(nums);


main.cpp:192:17: error: use of undeclared identifier 'complexSum'
intresult = complexSum(nums);


main.cpp:202:42: error: use of undeclared identifier 'complexSum'
ComplexNumber<double> doubleresult = complexSum(doublenums);
complexSum() is a member function of ComplexNumber. Maybe you meant to put it outside the class.

main.cpp:81:27: error: invalid operands to binary expression
('ComplexNumber<char>' and 'Number<char>')
ComplexNumber<T> c = a*b;
ComplexNumber::operator*() only takes a ComplexNumber as a RHS operand. You need to define a ComplexNumber::operator*(Number &) overload.

main.cpp:82:22: error: no viable conversion from 'Number<char>' to
'ComplexNumber<char>'
ComplexNumber<T> d = b*a;
Number::operator*() returns a Number. Define ComplexNumber::ComplexNumber(const Number &).
Last edited on
I believe you were right about the first part, moving complexSum outside of the class, however I'm a bit confused by your second and third explanations, could you please explain/show a bit more?
I'm not sure how. What exactly is confusing you?
I'm not sure where in the header file i should place the definitions and how i should define the third explanation
The operator*() overload would go inside ComplexNumber, and the constructor should construct a ComplexNumber with a null imaginary part and a real part equal to that of the parameter, of course.
thank you!
Topic archived. No new replies allowed.