Problem understanding Inheritance

Hello again,

I working through the book C++ without Fear (2nd Ed), and have become stuck on Exercise 17.2.1.

The problem is as follows,

In previous chapters a 'Fraction' class was derived that gave the ability to store fractions - you entered in a Numerator (N) and Denominator (D) and the fraction with the lowest common denominator was stored inside the class.

The values for N and D were stored in int format.

To demonstrate inheritance, a new class called FloatFraction is derived from the Fraction class, whereby it is possible to turn a float into a fraction (eg. 2.2 = 11/5).

In the original Fraction class it was possible to add two fractions together using a 'Fraction operator+(const Fraction &other)' function (eg. 1/4 + 1/4 = 1/2)

The exercise is to extend this ability to add together two FloatFractions.

I've spent quite a while trying but this task seems beyond me. I've included the full code below (although I've removed some of the non-necessary functions to save space, and the Fraction class is declared in the same code, whereby before it was in a separate file).

Adding a FloatFraction and a Fraction to yield a new Fraction is possible

1
2
3
4
5
6
 	FloatFraction floatfract1(2.2), floatfract2;
	Fraction fract1(1,1), fract2;

	fract2 = floatfract1 + fract1;
	
	cout << fract2;


prints 16/5 as expected.

But when attempting to add a FloatFraction and a Fraction to yield a new FloatFraction

1
2
3
4
5
6
  	FloatFraction floatfract1(2.2), floatfract2;
	Fraction fract1(1,1), fract2;

	floatfract2 = floatfract1 + fract1;
	
	cout << fract2;


gives the following error

error: no match for 'operator=' in 'floatfract2 = Fraction::operator+(const Fraction&)(((const Fraction&)((const Fraction*)(& fract1))))'

Thanks for your help

FULL CODE:

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
#include <iostream>
//#include "Fract.h"

#include <iostream>

using namespace std;


// ==================================
class Fraction {
private:
	int num, den; // Numerator and denominator.

public:
		
	Fraction() {set(0, 1);}
	Fraction(int n, int d) {set(n, d);}
	Fraction(int n) {set(n, 1);}
	Fraction(const Fraction &src);
	void set(int n, int d)
	{num = n; den = d; normalize();}
	int get_num() const {return num;}
	int get_den() const {return den;}
	Fraction add(const Fraction &other);
	
	Fraction operator+(const Fraction &other)
	{return add(other);}
	
	friend ostream &operator<<(ostream &os, Fraction &fr);
private:
	void normalize(); // Convert to standard form.
	int gcf(int a, int b); // Greatest Common Factor.
	int lcm(int a, int b); // Lowest Common Denom.
};
//=============================================


// Note: Fract.cpp must be compiled and linked into
// the project.
class FloatFraction : public Fraction {
public:
	FloatFraction(double n){set_float(n, 1);}
	
	void set_float(double dn, double dd);
	
	FloatFraction() {set(0, 1);}
	FloatFraction(int n, int d) {set(n, d);}
	FloatFraction(int n) {set(n, 1);}
	FloatFraction(const FloatFraction &src)
	{set(src.get_num(), src.get_den()); }
	
	double get_float() {
		double x = get_num();
		return x / get_den();
	}
	
};
int main() {
		
	FloatFraction floatfract1(2.2), floatfract2;
	Fraction fract1(1,1), fract2;

	floatfract2 = floatfract1 + fract1;
	
	cout << fract2;	
	

	return 0;
}


void FloatFraction::set_float(double dn, double dd){
	int n, d;
	n = static_cast<int> (dn * 1000);
	d = static_cast<int> (dd * 1000);
	//	cout << "Setting: " << n << " / " << d << endl;
	
	set(n, d);
}


//===========================================
Fraction::Fraction(Fraction const &src) {
	num = src.num;
	den = src.den;
}
// Normalize: put fraction into standard form, unique
// for each mathematically different value.
//
void Fraction::normalize(){
	// Handle cases involving 0
	if (den == 0 || num == 0) {
		num = 0;
		den = 1;
	}
	// Put neg. sign in numerator only.
	if (den < 0) {
		num *= -1;
		den *= -1;
	}
	// Factor out GCF from numerator and denominator.
	int n = gcf(num, den);
	num = num / n;
	den = den / n;
}
// Greatest Common Factor
//
int Fraction::gcf(int a, int b){
	if (b == 0)
		return abs(a);
	else
		return gcf(b, a%b);
}

// Lowest Common Multiple
//
int Fraction::lcm(int a, int b){
	int n = gcf(a, b);
	return a / n * b;
}
Fraction Fraction::add(const Fraction &other) {
	int lcd = lcm(den, other.den);
	int quot1 = lcd/den;
	int quot2 = lcd/other.den;
	return Fraction(num * quot1 + other.num * quot2,
					lcd);
}
/*Fraction Fraction::add(const Fraction &other) {
 int lcd = lcm(get_den(), other.get_den());
 int quot1 = lcd/get_den();
 int quot2 = lcd/other.get_den();
 return Fraction(get_num() * quot1 + other.get_num() * quot2,
 lcd);
 }*/


// ---------------------------------------------------
// FRACTION CLASS FRIEND FUNCTION
ostream &operator<<(ostream &os, Fraction &fr) {
	os << fr.num << "/" << fr.den;
	return os;
}

//=================================================










But when attempting to add a FloatFraction and a Fraction to yield a new FloatFraction


I think your mistake is trying to do this. FloatFraction expects a float, but you are assigning it the sum of two fractions (which turns out to be a fraction).
You need to define more operators!

Can you add two FloatFractions? I don't see a definition for operator+ in FloatFractions.
Oh! I've fixed it so I can now add two FloatFractions by adding an operator+ in the FloatFraction class.

However is there no way to inherit this ability from the original Fraction class without having to create a new operator + in the FloatFraction class? As I thought this was the purpose of the exercise?

Thanks
Well think about it. If anything, it inherits the function:
Fraction operator+(const Fraction &other)
(i.e. it adds a Fraction to a FloatFraction).

That function isn't what you want. You need
FloatFraction operator+(const FloatFraction& other)
(adds two FloatFractions).

I may be wrong, but I think this describes the situation.
You were inheriting the + operator action from the fraction class. The problem is it wasn't designed to work with FloatFunctions, which it doesn't even know exist at the time of the + operator definition.

I believe you could forward declare the FloatFraction class and inherit the ability you want as well, like this:

class FloatFraction;
FloatFractionoperator+(const FloatFraction&other)
{return add(other);}

but that's probably not the point of the excercise ;)
(also my syntax might be off. I'm learning c++ myself.)
Sorry!

Just checked my copy of Stroustrup.

It all works for me if I add an additional constructor to FloatFraction

FloatFraction(const Fraction &src)
{set(src.get_num(), src.get_den()); }

No need for operator+ to re-declared here as there are no new data members added to FloatFraction. It safely inherited in this case.

These tests all behave OK

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
	{
		FloatFraction fract1(1, 2);
		Fraction fract2(1, 4);
		Fraction fract3 = fract1 + fract2;
		cout << fract3 << endl;
	}

	{
		FloatFraction fract1(0.5);
		FloatFraction fract2(0.25);
		Fraction fract3 = fract1 + fract2;
		cout << fract3 << endl;
	}

	{
		FloatFraction fract1(0.5);
		Fraction fract2(1, 4);
		FloatFraction fract3 = fract1 + fract2;
		cout << fract3 << endl;
	}

	{
		Fraction fract1(1, 4);
		FloatFraction fract2(0.5);
		FloatFraction fract3;
		fract3 = fract1 + fract2;
		cout << fract3 << endl;
	}


3/4
3/4
3/4
3/4


They all work OK if fract3 is declared as a Fraction, too.

Notes
1 - it is usual to declare operator= when you declare a copy constructor
2 - operator= is not inherited by derived classes (Stroustrup, C++ Prog Lang)
Last edited on
Thank-you very much, that works just fine now.

Topic archived. No new replies allowed.