Polymorphic calls not working!!

Shape<---Triangle<---IsoTriangle

If I run code below I get the following error
IsoTriangle.cpp:36:8: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘Shape’)
cout << *shp << endl;

1
2
3
4
5
6
7
8
9
  IsoTriangle rect(10);
  Shape* shp = &rect;
  //cout << typeid(shp).name() << endl;
  //cout << typeid(*shp).name() << endl;

  //This line causes error saying compiler cannot find operator<<
  cout << *shp << endl;
  //rect.draw('2', 'w');
}



My Shape header
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
#ifndef SHAPE_H
#define SHAPE_H
#include<string>
#include<vector>
#include<iostream>
using namespace std;

class Shape {
private:
	static int num;
	int id_num;
	string generic_name;
	string descriptive_name;
public:

	vector< vector<char> > str_rep;

	//getters
	virtual int  get_id() const;
	virtual string  get_generic_name() const;
	virtual string  get_descriptive_name() const;
	int num_incr();

	//setters
  virtual void set_generic_name(string name);
	virtual void  set_desciptive_name(string name);
	virtual void  set_id(int id);

	//pure_virtuals
	virtual void generate_string_representation() = 0;
	virtual void scale(int factor) = 0;
	virtual float area() const = 0;
	virtual float perimeter() const = 0;
	virtual vector< vector<char> > draw(char penChar, char fillChar) const = 0;
	virtual float calculate_box_height() const = 0;
	virtual float calculate_box_width() const = 0;
	virtual float scrn_area() const = 0;
	virtual float scrn_perimeter() const = 0;
	virtual string toString() const = 0;
	// friend ostream& operator<<(ostream& os, const vector< vector<char> >& grid);
	// friend ostream& operator<<(ostream& os, const Shape& obj);
};

#endif


Shape cpp
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
#include"Shape.h"


int Shape::num = 0;

int Shape::get_id() const{
	return this->id_num;
}

string Shape::get_generic_name() const{
	return this->generic_name;
}

string Shape::get_descriptive_name() const{
	return this->descriptive_name;
}

int Shape::num_incr() {
	Shape::num++;
	return Shape::num;
}

void Shape::set_generic_name(string name) {
	this->generic_name = name;
}

void Shape::set_desciptive_name(string name) {
	this->descriptive_name = name;
}

void Shape::set_id(int id) {
	this->id_num = id;
}


My triangle header
1
2
3
4
5
6
7
8
9
#ifndef TRIANGLE_H
#define TRIANGLE_H
#include"Shape.h"

class Triangle: public Shape{
};

#endif


IsoTriangle.h
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
#ifndef IsoTriangle_H
#define IsoTriangle_H
#include"Triangle.h"
#include<typeinfo>
#include<string>
#include <cmath>

class IsoTriangle : public Triangle {
	public:
		int height;
		int base;
		IsoTriangle(int base);
		~IsoTriangle();

		void generate_string_representation(){
			this->str_rep.resize(this->height);
      int point = (this->base / 2) ;
      int count = 0;
			for (int x = 0; x <= this->height - 1; x++) {
				this->str_rep[x].resize(this->base);
				for (int y = 0; y <= this->base - 1; y++) {
          if(y >= point - count && y<= point + count){
            this->str_rep[x].push_back('*');
          }else{
            this->str_rep[x].push_back(' ');
          }
				}
        count++;
			}
		}

		void scale(int factor) {
			if (this->base + (2 * factor) >= 1) {
				this->base = this->base +  (2 * factor);
        this->height = (this->base + 1)/2;
				this->generate_string_representation();
			}
		}

		float area() const{
			return float(float(this->height * this->base)/2);
		}

		float perimeter() const{
      int b_sq = this->base * this->base;
      int h_sq = this->height * this->height;
			return float(this->base + (2 * pow(((.25 * b_sq) + h_sq), .5)));
		}

		vector< vector<char> > draw(char penChar, char fillChar) const{
			const int b = this->base;
			const int h = this->height;
			vector< vector<char> > temp(h, vector<char>(b));
      int point = (this->base / 2) ;
      int count = 0;
			for (int x = 0; x <= this->height - 1; x++) {
				for (int y = 0; y <= this->base - 1; y++) {
          if(y >= point - count && y<= point + count){
            temp[x].push_back(penChar);

          }else{
            temp[x].push_back(fillChar);

          }
				}
        count++;
			}
			return temp;
		}

		float calculate_box_height() const{
			return this->height;
		}

		float calculate_box_width() const{
			return this->base;
		}

		float scrn_area() const{
			return float(this->height * this->height);
		}

		float scrn_perimeter() const{
			return float(4 * (this->height - 1));
		}

    string toString() const{
      string abcd;
      abcd = string("Shape Information") + "\n";
      abcd = abcd + "-----------------" + "\n";
      abcd = abcd + "Static type: " + typeid(this).name() + "\n";
      abcd = abcd + "Dynamic type: " + typeid(this).name() + "\n";
      abcd = abcd + "Generic Name: " + this->get_generic_name() + "\n";
      abcd = abcd + "Description: " + this->get_descriptive_name() + "\n";
      abcd = abcd + "id: " + to_string(this->get_id()) + "\n";
      abcd = abcd + "B. box width: " + to_string(this->calculate_box_width()) + "\n";
      abcd = abcd + "B. box height: " + to_string(this->calculate_box_height()) + "\n";
      abcd = abcd + "Scr area: " + to_string(this->scrn_area()) + "\n";
      abcd = abcd + "Geo area: " + to_string(this->area()) + "\n";
      abcd = abcd + "Scr Perimeter: " + to_string(this->scrn_perimeter()) + "\n";
      abcd = abcd + "Geo Perimeter: " + to_string(this->perimeter()) + "\n";
      return abcd;
    }

		friend ostream& operator<<(ostream& os, const Shape& obj) {
			os << "Shape Information" << endl;
			os << "-----------------" << endl;
			os << "Static type: " << typeid(&obj).name() << endl;
			os << "Dynamic type: " << typeid(obj).name() << endl;
			os << "Generic Name: " << obj.get_generic_name() << endl;
			os << "Description: " << obj.get_descriptive_name() << endl;
			os << "id: " << obj.get_id() << endl;
			os << "B. box width: " << obj.calculate_box_width() << endl;
			os << "B. box height: " << obj.calculate_box_height() << endl;
			os << "Scr area: " << obj.scrn_area() << endl;
			os << "Geo area: " << obj.area() << endl;
			os << "Scr Perimeter: " << obj.scrn_perimeter() << endl;
			os << "Geo Perimeter: " << obj.perimeter() << endl;
      return os;
		}
};

ostream& operator<<(ostream& os,  const vector< vector<char> >& grid) {
  for (const vector<char>& vec : grid) {
    for (const char& ch : vec) {
      os << ch;
    }
    os <<"\n";
  }
  return os;
}

#endif // !IsoTriangle_H


IsoTriangle.cpp
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
#include "IsoTriangle.h"
#include <iostream>

IsoTriangle::IsoTriangle(int base) {
	if(base<=0){
		std::cout << "Cannot pass values less than or equal to 0 \n";
		this->~IsoTriangle();
	}
  if(base%2==0){
    base++;
  }
	this->base = base;
  this->height = (base + 1)/2;
	this->set_id(this->num_incr());
  this->set_generic_name("IsoTriangle");
  this->set_desciptive_name("Generic IsoTriangle");
}

IsoTriangle::~IsoTriangle() {

}

int main()
{
	IsoTriangle rect(10);
	IsoTriangle rect_1(0);
	IsoTriangle rect_2(-10);
	cout << rect << endl;
  cout << rect.draw('2', 'w') << endl;
  rect.scale(2);
  cout << rect.draw('2', 'w') << endl;
  cout << rect.toString() << endl;
  Shape* shp = &rect;
  cout << typeid(shp).name() << endl;
  cout << typeid(*shp).name() << endl;
  cout << *shp << endl;
  //rect.draw('2', 'w');
}
There is no operator<< that takes a Shape as argument.
There is operator<< with Shape argument somehow its indented badly IDK why
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
friend ostream& operator<<(ostream& os, const Shape& obj) {
			os << "Shape Information" << endl;
			os << "-----------------" << endl;
			os << "Static type: " << typeid(&obj).name() << endl;
			os << "Dynamic type: " << typeid(obj).name() << endl;
			os << "Generic Name: " << obj.get_generic_name() << endl;
			os << "Description: " << obj.get_descriptive_name() << endl;
			os << "id: " << obj.get_id() << endl;
			os << "B. box width: " << obj.calculate_box_width() << endl;
			os << "B. box height: " << obj.calculate_box_height() << endl;
			os << "Scr area: " << obj.scrn_area() << endl;
			os << "Geo area: " << obj.area() << endl;
			os << "Scr Perimeter: " << obj.scrn_perimeter() << endl;
			os << "Geo Perimeter: " << obj.perimeter() << endl;
      return os;
}
Last edited on
Ah, I see. I wasn't expecting it to be in the IsoTriangle class.

When you declare a function as a friend inside a class it will not be considered during the usual lookup process outside the class.

1
2
3
4
5
6
7
8
9
10
class A
{
	friend void f();
};

int main()
{
	A a;
	f(); // error: ‘f’ was not declared in this scope
}


The reason it normally works for the << and >> operators is thanks to something called argument-dependent lookup (ADL). If a class object is passed as argument to a function the compiler will in addition look for a matching function within that class.

1
2
3
4
5
6
7
8
9
10
class A
{
	friend void g(A);
};

int main()
{
	A a;
	g(a); // This works fine thanks to ADL.
}


In your code you are passing a Shape reference to the << operator but it cannot find a match. There is no such operator declared in the global scope, nor is it in the Shape class. The IsoTriangle class is not considered.
Topic archived. No new replies allowed.