简短问题:
B类有一个ptr到C类,它的D类有一个ptr到B类
通过复制将类B分配给A类中的数组,期望看到ptr指向数组中的新实例而不是原始实例但是失败。
我已经能够做一些解决方法,但我想知道为什么我原来的方法失败了。
更详细的解释如下,并且还会发布重现问题的代码
任何能够解释正在发生的事情的人都会受到赞赏。
共有6个课程:
类CastInfo //包含一个Character *
class Skill //抽象类,包含CastInfo
class Movvement:public Skill
班级Move1:公共运动
class Character //包含一个Movement *,在实践中将是Move1 *
class Squad //包含一个Character
数组具有以下关系:
CastInfo中的字符*应指向拥有该技能的角色 是CastInfo的所有者
将技能分配给角色时,CastInfo中的角色*指向该角色
应该复制Squad数组中的Character,因此会有2个实例,而CastInfo中的Character *也应该指向Squad数组中的Character而不是原始实例
期待的结果是:
move1!= ch1.move1!= squad.ch [0] .move1(已经满意)
ch1.move1-> cast_info.caster ==& ch1!= squad.ch [0] .move1-> caster_info.caster(这是问题)
输出有2种情况(尝试过):
在Squad的构造函数中: 如果使用
characters_[i] = characters[i];
正确复制了该角色,但该技能位于同一地址
move1: 00000270E6093500
ch1: 000000BC6DCFF378
ch1.move1: 00000270E6093E60
ch1.move1->cast_info.caster: 000000BC6DCFF378
squad.ch[0]: 000000BC6DCFF3E0
squad.ch[0].move1: 00000270E6093E60
squad.ch[0].move1->cast_info.caster: 000000BC6DCFF378
如果使用
characters_[i] = Character(characters[i]);
该角色被正确复制,但缺少技能(指向一些奇怪的位置)
move1: 00000230FDCEF080
ch1: 00000058A11DF548
ch1.move1: 00000230FDCEF260
ch1.move1->cast_info.caster: 00000058A11DF548
squad.ch[0]: 00000058A11DF5B0
squad.ch[0].move1: 00000230FDCEF0E0
squad.ch[0].move1->cast_info.caster: 00000058A11DF378
在第一种情况下,我想这可能是因为我没有重载operator =,所以只复制地址。我试图超载它,但它引起了更多的问题。 (例如使用Builder.Build()时)
在第二种情况下,我希望它首先调用复制构造函数,它触发调用SetCaster()的SetMove1()。如图所示克隆了move1,但我无法理解为什么施法者没有正确更新。 (虽然调用operator =在construnction之后,地址应该保持不变。)
以下代码应重现此问题:
motion.h
#pragma once
class Character;
struct CastInfo
{
Character* caster;
int coeff;
};
class Skill
{
public:
CastInfo cast_info;
Skill() {};
~Skill() {};
virtual void DoSomething() = 0;
};
class Movement : public Skill
{
public:
Movement();
~Movement();
virtual void DoSomething() { ; }
virtual Movement* Clone() const { return new Movement(*this); }
};
class Move1 : public Movement
{
public:
Move1() { cast_info.coeff = 123; }
void DoSomething() { ; }
virtual Move1* Clone() const { return new Move1(*this); }
};
class Move2 : public Movement
{
public:
void DoSomething() { ; }
};
motion.cpp:
#include "motion.h"
Movement::Movement() { }
Movement::~Movement() { }
test.h:
#pragma once
#include <string>
#include <vector>
#include "motion.h"
#define SQUAD_SIZE 6
extern Movement* null_movement;
class Character
{
public:
class Builder;
Character();
~Character();
Character(const Character& character);
Character& SetMove1(Movement* skill);
public:
int id_;
Movement* move1_ = null_movement;
Movement* move2_ = null_movement;
Character(int id) : id_(id) { ; }
void SetCaster();
};
class Character::Builder : public Character
{
public:
Builder& SetId(int i) { id_ = i; return *this; }
Character Build() { return Character(id_); }
};
class Squad
{
public:
class Builder;
Squad() { }
Squad(const Squad& squad);
~Squad() { }
public:
Character characters_[SQUAD_SIZE];
Squad(Character* characters);
};
class Squad::Builder :public Squad
{
public:
Builder& SetCharacter(const Character& character, const int position) { characters_[position] = character; return *this; }
Squad Build() { return Squad(characters_); }
};
TEST.CPP
#include <iostream>
#include "test.h"
Movement* null_movement = new Move2();
Character::Character() : id_(0) { }
Character::~Character() {}
Character::Character(const Character& character) {
id_ = character.id_;
SetMove1(character.move1_);
}
Character& Character::SetMove1(Movement* move1) {
if (!move1) return *this;
move1_ = move1->Clone();
SetCaster();
return *this;
}
void Character::SetCaster() {
if (move1_ != NULL) move1_->cast_info.caster = this;
}
Squad::Squad(const Squad& squad) {
*this = squad;
}
Squad::Squad(Character* characters) {
for (int i = 0; i < SQUAD_SIZE; i++) {
//characters_[i] = characters[i]; //character copied, skill same address
characters_[i] = Character(characters[i]); //character copied, skill missing
}
}
的main.cpp
#include <iostream>
#include "test.h"
#include "motion.h"
int main() {
Move1* move1 = new Move1();
std::cout << "move1: " << move1 << std::endl;
Character ch1 = Character::Builder().SetId(1).Build();
Character ch2 = Character::Builder().SetId(2).Build();
ch1.SetMove1(move1);
std::cout << "ch1: " << &ch1 << std::endl;
std::cout << "ch1.move1: " << (ch1.move1_) << std::endl;
std::cout << "ch1.move1->cast_info.caster: " << (ch1.move1_->cast_info.caster) << std::endl;
Squad squad = Squad::Builder().SetCharacter(ch1, 0).SetCharacter(ch2, 1).Build();
std::cout << "squad.ch[0]: " << &(squad.characters_[0]) << std::endl;
std::cout << "squad.ch[0].move1: " << (squad.characters_[0].move1_) << std::endl;
std::cout << "squad.ch[0].move1->cast_info.caster: " << (squad.characters_[0].move1_->cast_info.caster) << std::endl;
system("PAUSE");
return 0;
}
如前所述,我有一个解决方法来实现我的目标:
创建另一个方法,在Squad中遍历数组,并调用每个Character的SetCaster()方法。
void Squad::SetCaster() {
for (int i = 0; i < SQUAD_SIZE; i++) {
characters_[i].SetCaster();
}
}
但我认为这很脏,因为每次在Builder :: Builder()之后,必须调用SetCaster(),这是不直观且容易出错的。
答案 0 :(得分:0)
我想我发现了问题,如下图所示:
问题在于
Squad::Squad(Character* characters) {
for (int i = 0; i < SQUAD_SIZE; i++) {
//characters_[i] = characters[i]; //character copied, skill same address
characters_[i] = Character(characters[i]); //character copied, skill missing
}
}
如上所述,使用注释行只是复制值,这是不正确的。
什么
characters_[i] = Character(characters[i]); //character copied, skill missing
如下:
创建一个Character,通过调用Character的构造函数,该对象位于地址A.调用SetMove1(),调用SetCaster()。 cast_info中的指针正确指向A.
将对象分配给其地址位于地址B的characters_ [i],,因为在创建Squad时分配了字符_的地址。由于我没有重载Character :: operator =,指针仍然指向地址A
构造函数完成后,Squad返回。
这就是原因
std::cout << "squad.ch[0].move1->cast_info.caster: " << (squad.characters_[0].move1_->cast_info.caster) << std::endl;
显示第三个地址(地址A)既不是&#;(字符[0])(地址B)也不是&amp; ch1(原始字符的地址)
解决方案是重载operator =或者在for循环之后立即在构造函数中放入我的“workaround”(Squad :: SetCaster())。
如果有任何错误,或者有更好的解决方案,请纠正我。