tablica typu bazowego, a funkcje z klas pochodnych

0

Witam, chciałbym utworzyć wektor, do którego mogę wsadzić wszystkie pochodne klasy Point (klasa X to klasa pomocnicza, aby móc utworzyć wektor, nie działało z samym Point bo klasa abstrakcyjna), ale przy wywoływaniu funkcji to_string wywoływała się funkcja zależna od tego jaki obiekt jest obecnie w pętli for. W jaki sposób mogę to zrobić?

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

class Point{
public:
	Point(int x = 0, int y = 0) :_x(x), _y(y){}
	virtual ~Point(){}
	virtual void to_string() const=0{
		cout << "?"; 
	}
	int GetX() const{ return _x; }
	int GetY() const{ return _y; }
	void SetX(int x){ _x = x; }
	void SetY(int y){ _y = y; }
protected:
	int _x, _y;
};

class X: public Point{
public:
	X(int x=0,int y=0) :Point(x,y){}
	void to_string() const {
		cout << "X";
	}
};


class Tree : public X{
public:
	Tree(int x = 0, int y = 0):X(x,y){}
	virtual void to_string()const {
		cout << "T";
	}
};

class Wall : public X{
public:
	Wall(int x = 0, int y = 0) :X(x, y){}
	void to_string()const {
		cout << "W";
	}
};

class Grass : public X{
public:
	Grass(int x = 0, int y = 0) :X(x, y){
	}
	void to_string()const {
		cout << ".";
	}
};

int main(void){

	Tree T(1,2);
	Wall W(1,1);
	Grass G(2,2);

	std::vector < X > dane;
	dane.push_back(T);
	dane.push_back(W);
	dane.push_back(G);

	for (size_t i = 0; i < dane.size(); i++){
		dane[i].to_string();
	}
	return 0;
}
3
  1. Wywal X.

  2. Żeby korzystać z polimorfizmu, trzeba używać wskaźnika lub referencji. Tylko że zazwyczaj te wskaźniki wskazują na obiekty na stercie, więc warto trzymać np. unique_ptr<> zamiast gołych wskaźników. Za to nie wolno trzymać wskaźników do obiektów na stosie w unique_ptr<>.

  3. Nie możesz implementować czystej funkcji wirtualnej w miejscu deklaracji.

virtual void to_string() const=0{
        cout << "?"; 
    }
  1. Możesz dziedziczyć konstruktory klasy bazowej zamiast tworzyć
Tree(int x = 0, int y = 0):X(x,y){}

Całość:

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

class Point{
public:
    Point(int x = 0, int y = 0) :_x(x), _y(y){}
    virtual ~Point(){}
    virtual void to_string() const = 0; 
    
    int GetX() const{ return _x; }
    int GetY() const{ return _y; }
    void SetX(int x){ _x = x; }
    void SetY(int y){ _y = y; }
protected:
    int _x, _y;
};

void Point::to_string() const
{
    cout << "?"; 
}

class Tree : public Point
{
public:
    using Point::Point;
    virtual void to_string()const {
        cout << "T";
    }
};

class Wall : public Point
{
public:
    using Point::Point;
    void to_string()const {
        cout << "W";
    }
};

class Grass : public Point
{
public:
    using Point::Point;
    void to_string()const {
        cout << ".";
    }
};

int main(){

    Tree T(1,2);
    Wall W(1,1);
    Grass G(2,2);

    std::vector<Point*> dane;
    dane.push_back(&T);
    dane.push_back(&W);
    dane.push_back(&G);

    for (size_t i = 0; i < dane.size(); i++){
        dane[i]->to_string();
    }
    return 0;
}
0

rozumiem 1 i 3 punkt który poprawiłeś, w 2 zapewne są rzeczy pomocne do ułatwienia sobie pracy z alokacją pamięci, natomiast nie wiem w czym mógłby pomóc punkt 4. jeżeli dodałbym jakąś składową w klasie Tree, Wall etc to i tak musiałbym konstruktor pisać taki jaki był + dodać inicjowanie tej jednej składowej.

0

Tak, punkt 4 mówi o przypadku, kiedy masz pusty konstruktor klasy pochodnej i stworzyłeś go tylko po to by wołać konstruktor klasy bazowej.

0

ma być to mapka 2D, dopisałem trochę kodu i znowu wpadłem na pewien problem. utworzyłem wektor w którym chciałem przechowywać obiekty (Tree,Wall lub Grass). w linijce "*it2 = &T;" będzie funkcja zwracająca losowo wybrany obiekt, jednak póki co przypisuje zawsze Tree utworzone wcześniej, ponieważ nie mogę wymyślić jak wypisywać T,W lub G. linijka "*it2->to_string();" nie działa.

Tree T(1, 2);
	vector<vector<Point*> > v(ILOSC_WIERSZY, vector<Point*>(ILOSC_KOLUMN));
	vector <vector <Point*>>::iterator it;
	vector<Point*>::iterator it2;
	int wiersz=1, kolumna=1;
	for (it = v.begin(); it != v.end(); ++it) {
		for (it2 = it->begin(); it2 != it->end(); ++it2) {
			*it2 = &T; ;
			*it2->to_string();
			//cout << "(" << wiersz << ", " << kolumna << ")" << " ";
			//cout << *it2;
			++kolumna;
		}
		kolumna = 1;
		++wiersz;
		cout << endl;
	}
0

Następnym zamiast nie działa dołącz komunikat błędu

(*it2)->to_string();

-> ma wyższy priorytet niż *.

0

jasne, następnym razem tak zrobię. dołączę ostateczny kod jakby ktoś miał podobny problem, gdybyś ktoś widział jak to usprawnić/zrobić lepiej to proszę o komentarze.

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>
using namespace std;
#define ILOSC_WIERSZY 10
#define ILOSC_KOLUMN 10

class Point{
public:
	Point(int x = 0, int y = 0) :_x(x), _y(y){}
	virtual ~Point(){}
	virtual void to_string() const = 0;
protected:
	int _x, _y;
};

void Point::to_string() const {
	cout << "?";
}

class Tree : public Point{
public:
	Tree(int x = 0, int y = 0):Point(x,y){}
	virtual void to_string() const override {
		cout << "T";
	}
};

class Wall : public Point{
public:
	Wall(int x = 0, int y = 0) :Point(x, y){}
	virtual void to_string() const override {
		cout << "W";
	}
};

class Grass : public Point{
public:
	Grass(int x = 0, int y = 0) :Point(x, y){
	}
	virtual void to_string() const override {
		cout << ".";
	}
};

Point* ustaw(int wiersz, int kolumna){
	Point* ptr;
	if (wiersz == 1 || wiersz == ILOSC_WIERSZY || kolumna == 1 || kolumna == ILOSC_KOLUMN){
		ptr = new Wall(wiersz, kolumna);
		return ptr;
	} 

	float wylosowana_liczba = (float)((std::rand() % 100) + 1) / 100;
	if (wylosowana_liczba < 0.1){
		ptr = new Wall(wiersz, kolumna);
		return ptr;
	}
	else{
		if (wylosowana_liczba < 0.3){
			ptr = new Tree(wiersz, kolumna);
			return ptr;
		}
		else{
			ptr = new Grass(wiersz, kolumna);
			return ptr;
		}
	}
}

int main(void){
	srand(static_cast<unsigned int>(time(NULL)));
	//srand ( (unsigned int)time(NULL) );

	Tree T(1, 2);
	vector<vector<Point*> > v(ILOSC_WIERSZY, vector<Point*>(ILOSC_KOLUMN));
	vector <vector <Point*>>::iterator it;
	vector<Point*>::iterator it2;
	int wiersz=1, kolumna=1;
	for (it = v.begin(); it != v.end(); ++it) {
		for (it2 = it->begin(); it2 != it->end(); ++it2) {
			*it2 = ustaw(wiersz,kolumna);
			(*it2)->to_string();;
			//cout << "(" << wiersz << ", " << kolumna << ")" << " ";
			++kolumna;
		}
		kolumna = 1;
		++wiersz;
		cout << endl;
	}
	return 0;
}
0

A gdzie zwalniasz te obiekty tworzone przez new? Teraz patrz jeszcze raz na punkt 2 mojego pierwszego posta.

0

czy to dobre uzycie tych pointerow?

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <memory>
 
using namespace std;
#define ILOSC_WIERSZY 25
#define ILOSC_KOLUMN 50
 
class Point {
public:
    Point(int x = 0, int y = 0) :_x(x), _y(y) {}
    virtual ~Point() {}
    virtual void to_string() const =0;    
    int GetX() const { return _x; }                
    int GetY() const { return _y; }                
    void SetX(int x) { _x = x; }                    
    void SetY(int y) { _y = y; }                    
protected:
    int _x, _y;
};
 
void Point::to_string() const {
    cout << "?";
 
 
 
 
}
 
class Tree : public Point {
public:
    Tree(int x = 0, int y = 0) :Point(x, y) {}
    virtual void to_string() const override {      
        cout << "T";
    }
};
 
class Wall : public Point {
public:
    Wall(int x = 0, int y = 0) :Point(x, y) {}
    virtual void to_string() const override {
        cout << "W";
    }
};
 
class Grass : public Point {
public:
    Grass(int x = 0, int y = 0) :Point(x, y) {
    }
    virtual void to_string() const override {
        cout << ".";
    }
};
 
shared_ptr<Point> ustaw(int wiersz, int kolumna)
{
    shared_ptr<Point>ptr;
    if (wiersz == 1 || wiersz == ILOSC_WIERSZY || kolumna == 1 || kolumna == ILOSC_KOLUMN) {
        shared_ptr<Point> temp(new Wall(wiersz, kolumna));
        ptr = temp;
        return ptr;
    }
 
    float wylosowana_liczba = (float)((rand() % 100) + 1) / 100;
    if (wylosowana_liczba < 0.1) {
        shared_ptr<Point> temp(new Wall(wiersz, kolumna));
        ptr = temp;
        return ptr;
 
    }
    else {
        if (wylosowana_liczba < 0.3) {
            shared_ptr<Point> temp(new Tree(wiersz, kolumna));
            ptr = temp;
            return ptr;
        }
        else {
            shared_ptr<Point> temp(new Grass(wiersz, kolumna));
            ptr = temp;
            return ptr;
        }
    }
}
 
int main(void) {
    srand(static_cast<unsigned int>(time(NULL)));      
    //srand ( (unsigned int)time(NULL) );   
 
   
    vector<vector<shared_ptr<Point>> > v(ILOSC_WIERSZY, vector<shared_ptr<Point>>(ILOSC_KOLUMN));
    vector <vector <shared_ptr<Point>>>::iterator it;     
    vector<shared_ptr<Point>>::iterator it2;            
    int wiersz = 1, kolumna = 1;
    for (it = v.begin(); it != v.end(); ++it) {           
        for (it2 = it->begin(); it2 != it->end(); ++it2) {
 
            shared_ptr<Point> &ref = *it2;
 
            ref= ustaw(wiersz, kolumna);
            (*it2)->to_string();
 
           
            ++kolumna;
        }
        kolumna = 1;
        ++wiersz;
        cout << endl;
    }
 
 
    system("pause");
    return 0;
}

1 użytkowników online, w tym zalogowanych: 0, gości: 1