使用继承的函数而不是基函数(不是抽象函数)
Using inherited function instead of the base (not abstract)
例如,我想要名为chessman
和pawn
的类。我不能让chessman成为一个抽象类,因为我需要创建它的2D数组。pawn
类继承了chessman
,当我写这个时,我需要使用pawn
的move
函数:
chessman *cm = new pawn("a3", 'w');
cm->move(pos);
此代码使用chessman::move
。我能做些什么让它使用pawn
类中的那个?我的问题与这个问题非常相似,但我的函数不将pawn
作为自变量。在Java中,这很容易,因为您可以创建抽象类的数组,但在C++中,这只是令人困惑。
编辑:
以下是棋子类的定义(正如你所看到的,功能已经是虚拟的):
class chessman
{
public:
int i;
int j;
string name;
char color;
virtual bool move(string final_pos);
};
和典当:
class pawn : public chessman
{
public:
pawn(string pos, char color);
bool move(string final_pos);
};
我不能让棋子成为一个抽象类,因为我需要创建一个二维数组。
是的,你可以。您不创建chessman
对象的数组,而是创建指向chessman
对象的指针的数组。那么chessman
可以是抽象的(因为不应该从一开始就直接创建chessman
的实例)。
典当类继承了棋子,当我写这个时,我需要使用典当的移动功能
多态性为你处理这些。但是,为了使用多态对象数组,数组需要保存指向存储在内存其他地方的对象的指针/引用,而不是保存实际对象本身。
在Java中,这很容易,因为您可以创建抽象类的数组,但在C++中,这只是令人困惑。
你在C++中也可以做同样的事情。在Java中,对象是引用类型,因此它们总是由指针引用(Java语言只是对您隐藏了这些细节)。
试试这样的东西:
class chessman
{
private:
virtual bool isValidMove(string final_pos) = 0;
public:
int i;
int j;
string name;
char color;
chessman(string aname, char acolor);
bool move(string final_pos);
};
chessman::chessman(string aname, char acolor)
: name(aname), color(acolor)
{
}
bool chessman::move(string final_pos)
{
// validate that final_pos is a valid position on the board...
// validate that final_pos is a valid position for the piece being moved...
if (!isValidMove(final_pos))
return false;
// move to the position...
return true;
}
class pawn : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
pawn(string pos, char color);
};
pawn::pawn(string pos, char color)
: chessman("pawn", color)
{
//...
}
bool pawn::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this pawn to move to...
return ...;
}
class rook : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
rook(string pos, char color);
};
rook::rook(string pos, char color)
: chessman("rook", color)
{
//...
}
bool rook::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this rook to move to...
return ...;
}
class knight : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
knight(string pos, char color);
};
knight::knight(string pos, char color)
: chessman("knight", color)
{
//...
}
bool knight::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this knight to move to...
return ...;
}
class bishop : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
bishop(string pos, char color);
};
bishop::bishop(string pos, char color)
: chessman("bishop", color)
{
//...
}
bool bishop::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this bishop to move to...
return ...;
}
class queen : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
queen(string pos, char color);
};
queen::queen(string pos, char color)
: chessman("queen", color)
{
//...
}
bool queen::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this queen to move to...
return ...;
}
class king : public chessman
{
private:
virtual bool isValidMove(string final_pos);
public:
king(string pos, char color);
};
king::king(string pos, char color)
: chessman("king", color)
{
//...
}
bool king::isValidMove(string final_pos)
{
// validate that final_pos is a valid position for this king to move to...
return ...;
}
然后你可以做这样的事情:
chessman* white_pieces[16];
chessman* black_pieces[16];
for (int i = 0; i < 8; ++i)
{
white_pieces[i] = new pawn(...);
black_pieces[i] = new pawn(...);
}
for (int i = 8; i < 10; ++i)
{
white_pieces[i] = new rook(...);
black_pieces[i] = new rook(...);
}
for (int i = 10; i < 12; ++i)
{
white_pieces[i] = new knight(...);
black_pieces[i] = new knight(...);
}
for (int i = 12; i < 14; ++i)
{
white_pieces[i] = new bishop(...);
black_pieces[i] = new bishop(...);
}
white_pieces[14] = new queen(...);
black_pieces[14] = new queen(...);
white_pieces[15] = new king(...);
black_pieces[15] = new king(...);
并根据需要移动它们:
white_pieces[index]->move(pos);
...
black_pieces[index]->move(pos);
当然,完成后不要忘记清理:
for (int i = 0; i < 16; ++i)
{
delete white_pieces[i];
delete black_pieces[i];
}
若要自动进行清理,可以使用std::auto_ptr<chessman>
对象的数组。或者,在C++11及更高版本中,std::unique_ptr<chessman>
对象的std::vector
/std::array
。
在C++中,您可以创建一个指向棋子的某种指针(指针类型由对象所有权决定)的vector
(或可能在C++11中创建array
),并使棋子抽象。这只是一种稍微不同的思考方式。
(根据评论意见进行编辑):要使它选择合适的move
函数,请使用基类中的virtual
机制。我建议通过不具有公共虚拟功能来将接口与实现分离。相反,请使用公共非虚拟接口和私有或受保护的虚拟实现。您将使用一个私有实现,每个子类完全替换该功能,而当子类也需要调用父功能时,您将使用protected。
- C++ 继承:将子类传递给需要基类的函数并获取子类行为
- C++17 使用驱动类常量作为基类构造函数的参数来初始化基类构造函数
- 派生类(构造函数具有参数)和基类(构造函数缺少参数)之间没有可行的转换
- 设计模式,以避免不必要地添加抽象函数以适应新功能
- 从基类调用函数的多态性
- 在成员构造函数之后调用基类构造函数
- 在C++单元测试上下文中,抽象基类是否应将其他抽象基类作为函数参数
- 如何在将原始指针移动到基类构造函数之前从unique_ptr中提取原始指针
- 如何在具有相同函数名称的派生类中调用基类的函数
- 我不能访问基类的函数
- 根据模板参数引用不同基类的函数
- C++ 模板化基类的函数模板专用化
- 如何在C++中调用基类虚函数
- 指向从指针派生类成员函数的指针,指向基类成员函数
- C++:在共享对象中调用抽象基类构造函数/未定义的符号
- 如何在 C++ 中将参数传递给基类构造函数
- 从派生类调用的抽象基类成员函数
- 使用继承的函数而不是基函数(不是抽象函数)
- 从抽象基类成员函数调用纯虚拟函数
- 如何在c++中调用抽象基类的函数