Virtual methods in inheritance classes.


I have a class Quadrilateral that is made using aggregation of 4 Points (class). From Quadrilateral I have to create an inheritance chain of several other shapes. The first one in this chain is Trapezoid.
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
//
#ifndef POINT_H_INCLUDED
#define POINT_H_INCLUDED
#include "Equals.h"
#include <iostream>
#include <cmath>
using namespace std;

class Point
{
   friend ostream &operator << (ostream &out, const Point &p );
   friend istream &operator >> (istream &in, Point &p );
protected:
   double _x, _y; // coordinates
public:
   static const double INFINITE;
   Point();
   Point( double x, double y );
   Point ( Point& P);
   void SetAll( double x, double y );
   void SetDefault();
   double getX();
   double getY();
   double Distance( Point &P);
   double Slope( Point const &P) const;
   void operator =(Point &P);
};
#endif 

const double Point::INFINITE = pow(10.0,100.0);
ostream &operator << (ostream &out, const Point &p )
{
   out << "( " << p._x << ", " << p._y << " )" << flush;
   return out;
}

// extract from format ( x, y )
istream &operator >> (istream &in, Point &p )
{
   char d;
   in >> d >> p._x >> d >> p._y >> d;
   return in;
}

Point::Point()
{
   _x = _y = 0.0;
}

Point::Point( double x, double y )
{
   _x = x;
   _y = y;
}

Point::Point( Point &P)
{
	*this = P;
}
void Point::SetAll( double x, double y )
{
   _x = x;
   _y = y;
   return;
}
void Point::SetDefault()
{
	_x = _y = 0.0;	  
}
double Point::getX()
{
	return _x;
}
double Point::getY()
{
	return _y;
}
double Point::Distance( Point &P)  
{
	return sqrt( pow((_x - P._x), 2) + pow((_y - P._y), 2) );
}
double Point::Slope(Point const &P) const
{
	double slope;
	if ( isEqual( (_y - P._y), 0) ) 	//  0 in the numerator case
	{
		slope = 0.0;
	}
	if ( isEqual( (_x - P._x), 0) )		// 0 in the denominator case
	{
		slope = INFINITE;
	}
	else 
	{
		slope = (_y - P._y)/(_x - P._x);
	}
	return slope;
}
void Point::operator=(  Point &P)
{
	_x = P._x;
	_y = P._y;
}


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
//Quadrilateral.h
#ifndef QUADRILATERAL_H_INCLUDED
#define QUADRILATERAL_H_INCLUDED
#include "Point.h"
#include <iostream>
using namespace std;
class Quadrilateral : public Point
{
	protected:
		virtual void print(ostream &out, Point& a, Point& b, Point& c, Point& d);
		Point A;
		Point B;
		Point C;
		Point D;
	public:
		Quadrilateral();
		Quadrilateral(Point a, Point b, Point c, Point d );
		Quadrilateral(double x1, double y1, double x2, double y2, 
				  	  double x3, double y3, double x4, double y4);
		void setAll(Point a, Point b, Point c, Point d);
		double Perimeter();
		double Area();
		virtual void print(ostream &out, Quadrilateral &Q );
		friend ostream & operator <<(ostream &out, Quadrilateral &Q);
};
#endif

#include "Quadrilateral.h"
#include <iostream>
Quadrilateral::Quadrilateral() : A(), B() , C(), D()
{
	A.SetAll(0.0,0.0 );
	B.SetAll(6.0, -2.0);
	C.SetAll(4.0, 8.0);
	D.SetAll(1.0, 5.0);
}
Quadrilateral::Quadrilateral(Point a, Point b, Point c, Point d ): A(a), B(b), C(c), D(d) //Normal constructor using Points
{
	if(a.getX() >= b.getX() || a.getY() >= d.getY() || 
	   d.getX() >= c.getX() || b.getY() >= c.getY() )   //if coordinates are illegal,
	{													//set to default values
		cout << "\nIllegal Quadrilateral: "<<a<<b<<c<<d<<endl<<"Setting to: ";
		a.SetAll(0.0,0.0 );								
		b.SetAll(6.0, -2.0);
		c.SetAll(4.0, 8.0);
		d.SetAll(1.0, 5.0);	 
		cout<<a<<b<<c<<d<<endl;
		A=a;
		B=b;
		C=c;
		D=d;  
	}
	else
	{				//else
		setAll(a, b, c, d);	
	}      
}
Quadrilateral::Quadrilateral(double x1, double y1, double x2, double y2, //Normal constructor using coordinates
							 double x3, double y3, double x4, double y4) 
{
	Point a(x1, y1), b(x2, y2), c(x3, y3), d(x4, y4);
	setAll(a, b, c, d);	      	  
}
void Quadrilateral::setAll( Point a, Point b, Point c, Point d )
{
	A = a;	 
	B = b;
	C = c;
	D = d; 	   
}
double Quadrilateral::Perimeter()
{
	double total=0;
	total = A.Distance(B) + B.Distance(C) + C.Distance(D) + D.Distance(A);
	return total;
}
double Quadrilateral::Area()
{
	double t1=0, t2=0, a1 = A.Distance(D), b1 = C.Distance(D); 	  	  	//a1, b1, & c make up the 1st triangle (t1)
	double a2 = A.Distance(B), b2 = B.Distance(C), c = A.Distance(C);	//a2, b2, & c make up the 2nd (t2)
	//Heron's formula
	t1 = sqrt((a1+b1+c)*(b1-a1+c)*(a1-b1+c)*(a1+b1-c))/4;	 	
	t2 = sqrt((a2+b2+c)*(b2-a2+c)*(a2-b2+c)*(a2+b2-c))/4;
	return t1+t2;
}

ostream & operator <<(ostream &out, Quadrilateral &Q)
{
	//out <<"I'm a Quadrilateral: "<<Q.A<<Q.B<<Q.C<<Q.D<<flush;
	Q.print(out, Q.A, Q.B, Q.C, Q.D);
	return out;
}
void print(ostream &out, Point& a, Point& b, Point& c, Point& d) 
{
	out <<"I'm a Quadrilateral: "<<a<<b<<c<<d<<flush;
}


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
#ifndef TRAPEZIOD_H
#define TRAPEZIOD_H
#include "Quadrilateral.h"
class Trapezoid : public Quadrilateral
{
	protected:
		virtual void print(ostream &out);
	public:
		Trapezoid();
		Trapezoid (Point a, Point b, Point c, Point d);
		double Area();
		friend ostream & operator <<(ostream &out, Trapezoid &T);
		
};
#endif

#include "trapezoid.h"
Trapezoid::Trapezoid() : Quadrilateral()
{
	Point a(0.0, 0.0), b(4.0, 0.0), c(3.0, 2.0), d(1.0, 2.0);
	Quadrilateral::setAll(a, b, c, d);
}
Trapezoid::Trapezoid (Point a, Point b, Point c, Point d) : Quadrilateral(a,b,c,d)
{
	if(isEqual( a.Slope(b), c.Slope(d) ) )
	{
		Quadrilateral::setAll(a, b, c, d);
	}
	else 
	{
		Point a1(0.0, 0.0), b1(4.0, 0.0), c1(3.0, 2.0), d1(1.0, 2.0);
		cout<<"Illegal Trapezoid: "<<a<<b<<c<<d<<endl<<"Setting to: "<<a1<<b1<<c1<<d1<<endl;
		Quadrilateral::setAll(a1, b1, c1, d1);
	}
}
double Trapezoid::Area()
{
	double base = A.Distance(B), top = D.Distance(C), area=0, height=0;
	height = fabs( C.getY() - B.getY() );
	return ( ((base+top)/2) * height );
}
ostream & operator <<(ostream &out, Trapezoid &T)
{
//	  out<<"I'm a Trapezoid: "<<dynamic_cast<Quadrilateral&>(T)<<flush;
	T.print(out);
	//print(out, dynamic_cast<Quadrilateral&>(T));
	return out;
}
void print(ostream &out)
{
	out<<"I'm a Trapezoid: ";
	//Quadrilateral::print(out);
}


I have to make the Area and operator<< methods virtual and use a Quadrilateral pointer to point to the different shapes and return the area and print each shape and whatnot. With what I have now I get an "undefined reference to vtable" error in the constructors and I'm kinda stuck. Any ideas?
Last edited on
about undefined reference http://www.cplusplus.com/forum/general/113904/

so probably you forgot to implement a not pure virtual member function.
sadly, I cannot try to build your program as you forgot to post the `Equals.h' header

It seems that the error message is not really helpful, so check all the functions to see if they are defined.
The print's on line 93 (of Quadritateral) and on line 49 (of Trapezoid) need to be for each of their classes, else the vtables they are used in cannot be created.

void Quadrilateral::print(ostream &out, Point& a, Point& b, Point& c, Point& d)

void Trapezoid::print(ostream &out)

Also you will need to have:

1
2
3
4
void Quadrilateral::print(ostream &out, Quadrilateral &Q )
{
  out <<"I'm a Quadrilateral: " << Q << flush;
}


vtables contain pointers to methods that are virtual. Each instance of a class with any virtual methods will have one as its first entry, and will be dereferenced in calls to virtual methods at runtime.
See http://en.wikipedia.org/wiki/Virtual_method_table (has had errors)
Last edited on
Topic archived. No new replies allowed.