我有这个代码已经变成了一个小迷宫。 我有一个由名为MazePlace的 BASE 类组成的动态数组 ,我有两个 DERIVED 类,它们是wall和OpenSpace
基本上我想要的是读取具有可变尺寸的迷宫的文本文件,并逐个字符地读取文件并在指针数组中重新创建迷宫
LugarLaberinto*** lugares;
但是派生类OpenSpace具有允许我更改 OpenSpace 的方法,例如迷宫内的人。
所以我的问题是如何通过MazePlace类的指针访问OpenSpace类的方法?
在这里,我将代码与注释一起留下。(我试图使代码尽可能小以显示疑问,但我不能减少它更多。谢谢)
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
//####################################
//clase BASE lugar del laberinto
class LugarLaberinto
{
public:
virtual char mostrarCaracter()=0;
protected:
char caracter;
};
//####################################
//clase muro DERIVADA de lugar del laberinto
class muro : public LugarLaberinto
{
public:
muro();
~muro();
char mostrarCaracter();
};
muro::muro()
{
caracter = '#';
}
char muro::mostrarCaracter()
{
return caracter;
}
//####################################
//clase espacioAbierto DERIVADA de lugar del laberinto
class EspacioAbierto : public LugarLaberinto
{
public:
EspacioAbierto();
~EspacioAbierto();
char mostrarCaracter();
// funcion de la clase derivada
void hayAlguien(bool);
};
EspacioAbierto::EspacioAbierto()
{
caracter=' ';
}
char EspacioAbierto::mostrarCaracter()
{
return caracter;
}
void EspacioAbierto::hayAlguien(bool)
{
caracter='@';
}
//####################################
//clase laberinto
class laberinto
{
public:
//constructor que toma de un stream los valores del laberinto
laberinto (std::ifstream&, int, int);
~laberinto();
LugarLaberinto*** lugares;
LugarLaberinto* obtenerLugar(int, int);
};
laberinto::laberinto(ifstream& fin, int alto, int ancho)
{
char bloque;
string auxiliar;
lugares = new LugarLaberinto**[alto];
//fin.ignore();
for (int i=0; i< alto ; i++)
{
lugares[i] = new LugarLaberinto*[ancho];
// leo una linea completa del archivo laberinto
// y la guardo en auxiliar
getline(fin,auxiliar);
//cout << auxiliar;
for (int j=0; j< ancho; j++)
{
//leo cada uno de los caracteres y los almaceno en la variable bloque
bloque = auxiliar [j];
// Basado en si es un # o si es un espacio basio creo el puntero
//hacia lugar de laberinto
if (bloque=='#')
this->lugares[i][j] = new muro();
else
{
this->lugares[i][j] = new EspacioAbierto();
//########################
//aqui esta mi duda
// me gustaría acceder al metodo
// void hayAlguien(bool)
// a traves del puntero lugares
// sin embargo no se si sea posible
// o no se como hacerlo
/*
// aqui dice que la clase lugar laberinto no tiene
//un miembro llamado hayAlguien y bueno eso lo sé
// pero no quiero crear una funcion virtual para cada miembro
// de esta clase derivada
if (bloque=='@')
this->lugares[i][j]->hayAlguien(true);
*/
// encontré esta manera de hacerlo pero no se si es la única
// que es creando un nuevo objeto modificandolo y luego
// asignándolo, sin embargo no me siento totalmente cómodo
// pensando que tengo que crear objetos a cada instante que
// quiera modificar el objeto.
if (bloque=='@')
{
EspacioAbierto *aux= new EspacioAbierto();
aux->hayAlguien(true);
lugares[i][j]=aux;
}
}
//########################
cout << this->lugares[i][j]->mostrarCaracter();
}
cout << endl;
}
}
int main(int argc, char** argv) {
ifstream fin;
fin.open("laberinto.txt");
int alto = 10;
int ancho =10;
laberinto *nivel = new laberinto(fin, alto, ancho);
return 0;
}
最后附上文件 labyrinth.txt
##########
#@# #
# ##### #
# #
###### #
# #
# #######
# # #
# e#
##########
你有4种方式:
我在这里统治
如果您绝对确定您的指针引用了正确的类,则可以使用类型转换。使用这两种方法,您有责任检查指向基类的指针是否实际指向子类的实例。
这两种形式迫使编译器毫无疑问地接受您告诉它的内容,无论转换多么不合逻辑。
使用表达式
(clase_derivada *)puntero_a_clase_hija
:此语法继承自 C。您不应该使用它,因为如果您出于某种原因需要进行更改,则很难在代码行之间进行查看。
它与上一个类似,但我们使用保留字
reinterpret_cast
。这种语法更容易本地化;只需在文本中搜索
reinterpret_cast
即可找到它。它便于以后的更改,并使用更C++ 风格的语法。我很好,但以防万一
static_cast< >( )
.这可以被认为是比以前的方法更温和的方法。它不会强制编译器支持任何东西;如果涉及的类型明显不兼容,则会向我们显示错误。
C++ 帮帮我!
由于您使用的是 C++,因此您可以利用它并让语言运行时检查一个实例是否属于另一个实例的继承类。
要利用这一点,类必须具有虚拟方法,您已经在
LugarLaberinto
.dynamic_cast< >( )
.与上面类似:
正如你所看到的,我们做了一些不同的使用。如果可以进行转换,或者无法进行转换(例如,因为原始指针指向非子类) ,则运算符
dynamic_cast
返回一个指针。NULL
此外,如果我们将它与references一起使用,而不是返回
NULL
(这在 references 中是不可能的),std::bad_cast
如果无法进行转换,它将抛出异常。在 4 种可能的方式中,
dynamic_cast
它是唯一一种需要花费执行时间的方式;所有其他的都是在编译时完成的;后者受到最小的惩罚,因为检查指向类的指针是否实际上兼容(使用`VTABLE;因此需要虚拟方法)。@Trauma 的回答对我来说似乎是正确的,但总的来说,可以使用虚函数覆盖 if/downcast 机制。例如,您的基类可能是:
这种机制通常称为“服务请求”,如果对象可用,用户可以调用它来请求对象执行操作。您可以在中找到详细信息
来吧,另一种选择......访问者模式:
主要优点之一是不需要执行任何类型的转换,因为除非您做奇怪的事情,否则您将始终使用有效类型。
这种模式的逻辑起初有点冲突,但事实是它非常简单:
visit()
. 这个功能是虚拟的,这就是魔法开始起作用的地方。lista[i]->visit()
你调用visit()
当前类型对应的方法时(A
,B
或C
)会被调用。Visitor
每个实现都以不同的方式(VisitA
或VisitB
)VisitC
与对象交互。VisitX
如何Visitor
使用特定类型的对象,因此它可以访问其整个公共接口。如果这种模式是用接口实现的,或者在 C++ 的情况下,用抽象类实现,这种模式会非常强大。这样,您就可以拥有一个
Visitor
基本愚蠢的基类,然后拥有一整套特定的访问者来执行各种任务:编程的可能性是无穷无尽的,好处是访问逻辑只需编程一次。