难道一直是虚函数在作怪!?怎样才能安全地向上或向下转型,虚函数对内存布局有什么影响?GlobelDef.h:#define
难道一直是虚函数在作怪!?怎样才能安全地向上或向下转型,虚函数对内存布局有什么影响?
GlobelDef.h:
#define EMPTY 0
#define WHITEPIECE 1
#define BLACKPIECE 2
#define WHITETURN 3
#define BLACKTURN 4
#define GAMESTOP 5
#define BLACKWIN 6
#define WHITEWIN 7
#define NULL 0
//工具宏
#define ENSURE_RIGHTPIECE(whosturn) (whosturn-2)
//错误信息定义
#define OK 0
#define ERR_PIECE_CONFLICT -1
#define ERR_IGO_CONFLICT -2
#define ERR_OTHER -3
#include<iostream>
#include"GlobelDef.h"
using namespace std;
class CCoordinate
{
public:
CCoordinate();
virtual ~CCoordinate();
/*virtual*/ int setState(int pieceType);
//protected:
int mState;
};
CCoordinate::CCoordinate()
{
mState=EMPTY;
}
CCoordinate::~CCoordinate()
{
}
int CCoordinate::setState(int pieceType)
{
if(mState==EMPTY)
{
mState=pieceType;
return OK;
}
else
return ERR_PIECE_CONFLICT;
}
class CIgoCoordinate:public CCoordinate
{
public:
CIgoCoordinate();
~CIgoCoordinate();
int mLife;
int flag;
//int num;
};
CIgoCoordinate::CIgoCoordinate()
{
mLife=4;
flag=0;
}
CIgoCoordinate::~CIgoCoordinate()
{
}
int main()
{
CCoordinate** coorList=new CCoordinate*[19];
for (int y=0;y<19;y++)
coorList[y]= new CIgoCoordinate[19];
for(int i=0;i<19;i++)
for(int j=0;j<19;j++)
{
//std::cout<<i<<","<<j<<"state:"
std::cout<<((CIgoCoordinate**)coorList)[i][j].mLife<<" "; //这里输出的生命值是正常的。但却不能用虚函数setState对基类成员赋值?!
coorList[i][j].setState(1); //一旦我把这个函数在基类中声明为虚,程序就会崩溃!
if(j==18)
std::cout<<std::endl;
if(j==10)
std::cout<<"|";
}
std::cout<<"_________________________________________"<<std::endl;
for(int i=0;i<19;i++)
for(int j=0;j<19;j++)
{
//std::cout<<i<<","<<j<<"state:"
std::cout<<(coorList)[i][j].mState<<" ";
if(j==18)
std::cout<<std::endl;
}
system("pause");
}
虚函数?内存布局?向上转型
[解决办法]
肯定不行了,coorList的类型是CCoordinate**,如果按下标访问的话,是以CCoordinate的倍数大小进行访问的,然后你的数组确是以CIgoCoordinate的倍数大小来申请的
[解决办法]
CCoordinate** coorList=new CCoordinate*[19];
for (int y=0;y<19;y++)
coorList[y]= new CIgoCoordinate[19];
这个代码看得很头大,而且只有new没有delete , 这里直接老老实实用对象二维数组就可以。
CIgoCoordinate coorList[19][19] ;
程序崩溃估计是数组越界或野指针
[解决办法]
你是以派生类大小来申请,但是现在的问题是你使用的方式错了,你所想的内存分布跟正确的内存分布不一致,你应该用这样的方式
((CIgoCoordinate**) coorList)[i][j].setState(1);
[解决办法]
1,向应该上转型安全--- Liskov替换原则
2, 向下转型使用dynamic_cast
3, 你的程序中,有对象切割(object slice), 这是根本的错误。
4,尽量避免显示转型
[解决办法]
std::cout<< coorList[i][j]->getState()<<" ";
if(j==18)
std::cout<<std::endl;
}
for(int i=0;i<19;i++)
for(int j=0;j<19;j++)
{
delete coorList[i][j];
}
return 0;
}
[解决办法]
对象切割不是这个意思。
cordlist类型为T**,cordlist[y] = new SubT[19]; //这里发生了切割, 把19个SubT切成了19个T对象。简单来说cordlist[i][j]的静态/动态类型都是T,而不是T&或T*,所以完全没有动态性。
[解决办法]
做个可能不太恰当的比喻:
人想让狗帮忙逮只兔子,可是人说话狗听不懂,于是人发明了一种介乎人言和狗语之间的语言,即口令。
人想让电脑帮忙做计算,可是人话电脑听不懂,于是人发明了一种介乎人言和汇编机器码之间的语言,即C语言。
人对狗的口令得让人容易学、也得让狗容易懂。
C语言同样得让人容易学、也得让电脑容易懂。
相比之下C++、Java就是人学得费劲、电脑也经常闹不懂。
[解决办法]
CCoordinate* coorList[y]= new CIgoCoordinate[19]; 是不建议的
因为子类和父类内存大小不一定是一样的(大多数情况下是不一样的),
在大小不一样的情况下,CCoordinate+1和CIgoCoordinate+1的内存跨度是不一样的,会导致内存混乱
