Предыдущий пост -

Двойная диспетчеризация в С++.

Рубрика: C++, Дата: 31 March, 2013, Автор:
Tags:

Для классов Circle Square и Treangle, производных от Shape, определите функцию intersect() (пересечение), которая принимает два аргумента типа Shape* и вызывает другие функции, необходимые для выявления возможности пересечения фигур. Для решения этой задачи добавьте к классам соответствующие виртуальные функции. Можете не писать реальный код, выявляющий пересечение: просто убедитесь, что вызываются правильные функции. Решение таких задач называют двойной диспетчеризацией (double dispatch) или мультиметодом (multi-method).

Да опять же ничерта не понятно из условия. Чо это за двойная диспетчеризация? Да ну и задача. ппц.

Ну что ж разобрался я что такое двойная диспетчеризация – это как бы вызов функций производного класса через указатель на объект базового класса, через виртуальные функции. Например если функций две или три в базовом классе с разными объектами, то мы просто присваиваем указателю базового класса объект производного класса и вызываем виртуальную функцию, которой передаем два объекта, а уже исходя из типов этих объектов механизм виртуальных функций выбирает из нескольких функций какую функцию вызвать.

Определение конечно запутаное, тем более, что я его сам придумал. Лучше я приведу код:

#include <iostream>
using std::cout;
using std::endl;

class Square;
class Rectangle;
class Triangle;

class Shape
{
public:
	//virtual void intersec(Shape* a, Shape* b)=0;//f opredel9yucha9 perecechenie
	virtual void intersec(Shape* a, Square* b)=0;
	virtual void intersec(Shape* a, Rectangle* b)=0;
	virtual void intersec(Shape* a, Triangle* b)=0;
	//virtual void intersec(Shape*, Shape* ){cout <<"mu v baze"<<endl;};
	virtual void draw(int){cout <<"baza"<<endl;}
};

class Square : public Shape
{
public:
	void intersec(Shape* a, Square* b){cout <<"Square-Square"<<endl;}
	void intersec(Shape* a, Rectangle* b){cout <<"Square-Rectangle"<<endl;}
	void intersec(Shape* a, Triangle* b){cout <<"Square-Triangle"<<endl;}
};

class Rectangle : public Shape
{
public:
	virtual void intersec(Shape* a, Square* b){cout <<"Rectangle-Square"<<endl;}
	virtual void intersec(Shape* a, Rectangle* b){cout <<"Rectangle-Rectangle"<<endl;}
	virtual void intersec(Shape* a, Triangle* b){cout <<"Rectangle-Triangle"<<endl;}
	virtual void draw(int a){cout <<"Rectangle draw() "<<endl;}
};

class Triangle : public Shape
{
public:
	void intersec(Shape* a, Square* b){cout <<"Triangle-Square"<<endl;}
	void intersec(Shape* a, Rectangle* b){cout <<"Triangle-Rectangle"<<endl;}
	void intersec(Shape* a, Triangle* b){cout <<"Triangle-Triangle"<<endl;}
};

int main()
{
	Shape* Sh;
	Rectangle R;
	Triangle T;
	Square S;
	Sh=&R;
	Sh->intersec(&R,&T);
	Sh->draw(3);

	return 0;
}

В данном коде у нас имеется класс Shape и производные от него классы Triangle, Rectangla, Square и имеется виртуальный метод intersec() который принимает два разных объекта типа Shape. И в соответствии из типов этих объектов вызывается соответствующая функция в производных классах.

Например в данном примере Sh это указатель на базовый класс Shape. Мы ему присваиваем указатель на объект Rectangle (Sh=&R). Затем мы вызываем метод intersec() которому передаем указатели на два объекта типов Rectangle и Triangle (Sh->intersec(&R,&T)) , и у нас о чудо какая функция вызывается? Да правильно функция Rectangle::intersec(Shape* a, Rectangle* b); и выводиться строчка: “Rectangle-Triangle”. Вообщем в зависимости от передаваемых объектов вызывается та или иная функция. Так что так разобрались мы с этой двойной диспетчеризацией. Теперь давайте как мы попробуем относительно нашего класса чо нить сделать. Сделаем хотябы для двух для Line и для Rectangle.

Все доделал. Файл Window.h:

//klacc Window cozdaet oblact6 nxm
#ifndef WINDOW_H
#define WINDOW_H

#include "Point.h"
#include "Shape.h"

//prednamerennoe ob69vlenie
class Shape;

class Window
{
public:
	char mass[200][200];//massiv picselov
	int m;
	int n;
	Point* p;//nach koordinatu

	//konctryktor po ymolchaniyu
	Window()
	:m(0),n(0)
	{
		for(int i=0;i<200;i++)
		{
			for(int j=0;j<200;j++)
				mass[i][j]=' ';
		}
		p=new Point;//cozdaem ykazatel6 na ob6ekt
	}

	//konctryktor preobrazovani9
	Window(int m, int n)
	:m(m),n(n)
	{
		for(int i=0;i<200;i++)
		{
			for(int j=0;j<200;j++)
				mass[i][j]=' ';
		}
		p=new Point;//cozdaem ykazatel6 na ob6ekt
	}

	//vuzuvaetc9 dl9 zadani9 koordinat
	Point current(Point a)
	{
		p->x=a.x;
		p->y=a.y;
		return *p;
	}

	//vuzuvaetc9 dl9 pechati koordinat
	Point current()
	{
		cout <<p->x<<' '<<p->y<<endl;
		return *p;
	}

	//vuvod oblacti
	void print()
	{
		for(int i=0;i<n;i++)
		{
			for(int j=0;j<m;j++)
			{
				cout <<mass[i][j];
			}
			cout <<endl;
		}
	}

	void draw(Shape& a)
	{
		a.draw(&*this);//peredaem ykazatel6
	}
};

#endif

Файл Point.h:

//klacc Point
#ifndef POINT_H
#define POINT_H

struct Point
{
	int x;
	int y;
	//konctryktor po ymolchaniyu
	Point():x(0),y(0){}
	//konctryktor preobrazovani9
	Point(int a, int b):x(a),y(b){}
	//konctryktor kopii
	Point(const Point& a):x(a.x),y(a.y){}
	//zadanie koordinat
	void set(int a, int b){x=a;y=b;}
};

#endif

Файл Shape.h:

//bazovui klacc dl9 figyr
#ifndef SHAPE_H
#define SHAPE_H

#include <string>
using std::string;

class Window;
class Line;
class Rectangle;
#include "Point.h"
#include "Window.h"

#include <cstdlib>
using std::exit;

class Shape
{
public:
	Point e;//east(vocxod)
	Point w;//west(zaxod)
	Point n;//north(cever)
	Point s;//south(yug)

	Point ne;//levui verxnii
	Point nw;//pravui verxnii
	Point se;//levui nijnii
	Point sw;//levui nijnii
	Point c;//center
	int tol;
	string solid;

	void thickness(int a)
	{
		tol=a;
	}

	void outline(string s)
	{
		solid=s;
	}

	virtual void draw(Window*){};
	//konctryktor
	//Shape(){}
	Shape(const Point& a, const Point& b)
	:tol(2),solid("solid")
	{
		cout <<"k Shape"<<endl;
		//cout <<a.x<<' '<<a.y<<endl;
		//cout <<b.x<<' '<<b.y<<endl;
		nw=a;
		se=b;
		//cout <<se.x<<' '<<se.y<<endl;
		//cout <<nw.x<<' '<<nw.y<<endl;
		//cout <<se.x<<' '<<se.y<<endl;
		ne.x=b.x;
		ne.y=a.y;
		//cout <<ne.x<<' '<<ne.y<<endl;
		sw.x=a.x;
		sw.y=b.y;
		//cout <<sw.x<<' '<<sw.y<<endl;
		n.x=b.x/2;
		n.y=a.y/2;
		//cout <<n.x<<' '<<n.y<<endl;
		w.x=a.x/2;
		w.y=b.y/2;
		//cout <<w.x<<' '<<w.y<<endl;
		s.x=b.x/2;
		s.y=b.y;
		//cout <<s.x<<' '<<s.y<<endl;
		e.x=b.x;
		e.y=b.y/2;
		//cout <<e.x<<' '<<e.y<<endl;
		c.x=b.x/2;
		c.y=b.y/2;
		//cout <<c.x<<' '<<c.y<<endl;
		//exit(1);
	}

	virtual void intersect(const Shape* a, const Line* b)=0;
	virtual void intersect(const Shape* a, const Rectangle* b)=0;
};

#endif

файл Line.h:

//ob69vlenie klacca Line
#ifndef LINE_H
#define LINE_H
#include <cstdlib>
using std::exit;

#include "Shape.h"
#include "Point.h"

class Line : public Shape
{
	Point* a;
	Point* b;
	int kon;
public:
	//konctryktor
	//inicializaci9 camogo shape 9 tochek po diagonali
	Line(Point c, Point d)
	:Shape(c,d),kon(1)
	{
		a=new Point;
		a=&c;
		b=new Point;
		b=&d;
	}

	void arrowhead(int a)
	{
		kon=a;
	}

	void draw(Window* w)
	{

		if(solid=="solid")
		{
			cout <<"drow Line"<<endl;

			//cout <<a->mass[2][3]<<endl;
			int x=a->x;
			int y=a->y;
			int x1=b->x;
			int y1=b->y;
		cout <<"x= "<<x<<" y= "<<y<<" x1= "<<x1<<" y1= "<<y1<<endl;
			int x2;
			int y2;
			//cout <<"tol= "<<tol<<endl;exit(1);

			if(x<x1&&y<y1) //0,0 10,10
			{
				x2=x1-1;
				y2=x1-1;
				w->mass[x][y]=1;
				w->mass[x1][y1]=1;
				//naxodim tochki pr9moi

				while(x2>x&&y2>y)
				{
					w->mass[x2][y2]=1;
					x2=x2-1;
					y2=y2-1;
					//cout <<x2<<' '<<y2<<endl;
				}
			}
			if(x<x1&&y>y1)//0,20 10,10
			{
				x2=x+1;
				y2=y-1;
				w->mass[x][y]=1;
				w->mass[x1][y1]=1;
				//naxodim tochki pr9moi
			//	cout <<x2<<' '<<y2<<endl;
				while(x2<x1&&y2>y1)
				{
					w->mass[x2][y2]=1;
					x2=x2+1;
					y2=y2-1;
					//cout <<x2<<' '<<y2<<endl;
				}
			}
			if(x==x1&&y<y1)//0,0 0,10
			{
				//cout <<"mu tyt"<<endl;exit(1);
				x2=x+1;
				y2=y;
				if(kon==2)
					w->mass[x][y]=8;
				else
					w->mass[x][y]=1;
				//mass[x1][y1]=1;
				//naxodim tochki pr9moi
				cout <<x2<<' '<<y2<<endl;
				while(y1>x2)
				{
					w->mass[x2][y2]=1;
					x2=x2+1;
					y2=y2;
					//cout <<x2<<' '<<y2<<endl;
				}
			}

			if(y==y1&&x<x1)//0,0 10,0
			{
				cout <<"mu tyt"<<endl;
				x2=x+1;
				y2=y;
				w->mass[y][x]=8;
				//mass[x1][y1]=1;
				//naxodim tochki pr9moi
				cout <<x2<<' '<<y2<<endl;
				//exit(1);
				while(x1>x2)
				{
					w->mass[y][x2]=1;
					x2=x2+1;
					y2=y2;
					//cout <<x2<<' '<<y2<<endl;
				}
			}

			if(tol==3)
			{
				cout <<"tol= "<<tol<<endl;
				cout <<"drow Line"<<endl;

				//cout <<a->mass[2][3]<<endl;
				int x=a->x;
				int y=a->y+1;
				int x1=b->x;
				int y1=b->y+1;
			cout <<"x= "<<x<<" y= "<<y<<" x1= "<<x1<<" y1= "<<y1<<endl;
				int x2;
				int y2;
				//cout <<"tol= "<<tol<<endl;exit(1);

				if(x<x1&&y<y1) //0,0 10,10
				{
					x2=x1-1;
					y2=x1-1;
					w->mass[x][y]=1;
					w->mass[x1][y1]=1;
					//naxodim tochki pr9moi

					while(x2>x&&y2>y)
					{
						w->mass[x2][y2]=1;
						x2=x2-1;
						y2=y2-1;
						//cout <<x2<<' '<<y2<<endl;
					}
				}
				if(x<x1&&y>y1)//0,20 10,10
				{
					x2=x+1;
					y2=y-1;
					w->mass[x][y]=1;
					w->mass[x1][y1]=1;
					//naxodim tochki pr9moi
				//	cout <<x2<<' '<<y2<<endl;
					while(x2<x1&&y2>y1)
					{
						w->mass[x2][y2]=1;
						x2=x2+1;
						y2=y2-1;
						//cout <<x2<<' '<<y2<<endl;
					}
				}
				if(x==x1&&y<y1)//0,0 0,10
				{
					//cout <<"mu tyt"<<endl;
					x2=x+1;
					y2=y;
					w->mass[x][y]=1;
					//mass[x1][y1]=1;
					//naxodim tochki pr9moi
					cout <<x2<<' '<<y2<<endl;
					while(y1>x2)
					{
						w->mass[x2][y2]=1;
						x2=x2+1;
						y2=y2;
						//cout <<x2<<' '<<y2<<endl;
					}
				}

				if(y==y1&&x<x1)//0,0 10,0
				{
					cout <<"mu tyt"<<endl;
					x2=x+1;
					y2=y;
					w->mass[y][x]=8;
					//mass[x1][y1]=1;
					//naxodim tochki pr9moi
					cout <<x2<<' '<<y2<<endl;
					//exit(1);
					while(x1>x2)
					{
						w->mass[y][x2]=1;
						x2=x2+1;
						y2=y2;
						//cout <<x2<<' '<<y2<<endl;
					}
				}
				//exit(1);
			}
			//yctanovka v se tekychix koordinat

			w->current(se);
			//exit(1);
		}
		else if(solid=="dotted")
		{
			cout <<"dotted"<<endl;
			exit(1);
		}
		else if(solid=="dashed")
		{
			cout <<"dashed"<<endl;
			exit(1);
		}
	}

	virtual void intersect(const Shape* a, const Line* b)
	{
		cout <<"Line - Line"<<endl;
	}

	virtual void intersect(const Shape* a, const Rectangle* b)
	{
		cout <<"Line - Rectangle"<<endl;
	}
};

#endif

Файл Rectangle.h:

//klacc Rectangle (pr9moygol6nik)
#ifndef RECTANGLE_H
#define RECTANGLE_H

#include "Shape.h"
#include "Point.h"

class Rectangle : public Shape
{
	Point* a;
	Point* b;
public:
	//konctryktor
	//inicializaci9 camogo shape 9 tochek po diagonali
	Rectangle(Point c, Point d)
	:Shape(c,d)
	{
		a=new Point;
		a=&c;
		b=new Point;
		b=&d;
	}

	void draw(Window* w)
	{
		cout <<"drow Rectangle"<<endl;
		//exit(1);
		//cout <<a->mass[2][3]<<endl;
		int x=a->x;
		int y=a->y;
		int x1=b->y;
		int y1=b->x;
	/*//cout <<"x= "<<x<<" y= "<<y<<" x1= "<<x1<<" y1= "<<y1<<endl;
		int x2;
		int y2;

		int x=0;//2
		int y=0;//1
		int x1=4;//4
		int y1=5;//5*/
		cout <<"x= "<<x<<" y= "<<y<<" x1= "<<x1<<" y1= "<<y1<<endl;
		int x2;
		int y2;
		x2=x;
		y2=y;
		//cout <<"ddddd= ";
		//w->current();
		//mass[0][1]=1;
		//mass[1][0]=1;
		//mass[2][1]=1;
		w->mass[x][y]=1;
		w->mass[x1][y1]=1;
		x2=x;
		for(int i=x;i<=x1;i++)
		{
			w->mass[x2][y]=1;
			x2++;
		}
		x2=x;
		for(int i=x;i<=x1;i++)
		{
			w->mass[x2][y1]=1;
			x2++;
		}
		x2=y;
		for(int i=y;i<=y1;i++)
		{
			w->mass[x1][x2]=1;
			x2++;
		}
		x2=y;
		for(int i=y;i<=y1;i++)
		{
			//cout <<x1<<' '<<x2<<endl;
			w->mass[x][x2]=1;
			x2++;
		}
		//yctanovka v se tekychix koordinat

		w->current(se);
		//exit(1);
	}

	virtual void intersect(const Shape* a, const Line* b)
	{
		cout <<"Rectangle - Line"<<endl;
	}

	virtual void intersect(const Shape* a, const Rectangle* b)
	{
		cout <<"Rectangle - Rectangle"<<endl;
	}
};

#endif

И сам файл main.cpp:

//intersect() opredel9et perecechenie
#include <iostream>
using std::cout;
using std::endl;

#include "Point.h"
#include "Window.h"
#include "Shape.h"
#include "Line.h"
#include "Rectangle.h"

int main()
{
	Window w(60,30);

	Point p1(0,0);
	Point p2(15,15);
	Line L(p1,p2);
	Rectangle R(p1,p2);

	Shape* Sh;
	Sh=&L;
	Sh->intersect(&L,&L);

	return 0;
}

И все. Отлично ищется метод по значению объектов. 🙂 . А мы решаем следующую задачку.

Прикольный клипец: [youtube]http://www.youtube.com/watch?v=poYBVxS3C7s[/youtube]

  • Evgeny

    One more example:

    class Shape
    	{
    	public:
    		virtual int intersect(Shape* x) = 0;
    		virtual int intersect(Circle* x) = 0;
    		virtual int intersect(Triangle* x) = 0;
    	};
    
    	class Circle : public Shape
    	{
    	public:
    		int intersect(Shape* x)
    		{
    			return x->intersect(this);
    		}
    
    		int intersect(Circle* x) {return 1;};
    		int intersect(Triangle* x) {return 2;};		
    	};
    
    	class Triangle : public Shape
    	{
    	public:
    		int intersect(Shape* x)
    		{
    			return x->intersect(this);
    		}
    
    		int intersect(Circle* x) {return 3;};
    		int intersect(Triangle* x) {return 4;};		
    	};
    
    	int intersect(Shape* s1, Shape* s2)
    	{
    		return s1->intersect(s2);
    	}
rss