为什么缺少此嵌套类的指针

Why is the pointer in this nested class missing?

本文关键字:指针 嵌套 为什么      更新时间:2023-10-16

简单问题:

B类具有ptr的PTR,该类别具有D类D类PTR

通过复制将B类分配给A类中的数组,期望在数组而不是原始实例中看到PTR点到新实例,但失败了。

我已经能够进行一些解决方法,但是我想知道为什么我的原始方法失败了。

更详细的解释如下,并且重现问题的代码也已发布

任何能够解释发生的事情的人都将受到赞赏。

有6个类:

类Castinfo//包含一个字符*

类技能//抽象课,包含Castinfo

班级移动:公共技能

类移动1:公共运动

类字符//包含一个运动*,在实践中将移动1*

类小队//包含一个字符

的数组

具有以下关系:

  1. 角色* Castinfo中的角色*应指向拥有技能的角色是Castinfo的所有者

  2. 将技能分配给角色时,Castinfo中的字符*指向该字符

  3. 应该复制小队数组中的字符,因此将有2个实例,Castinfo中的字符*也应指向小队数组中的字符,而不是原始实例

期望结果是:

  1. move1!= ch1.move1!= squad.ch [0] .move1(这已经满足)

  2. ch1.move1-> cast_info.caster ==& ch1!= squad.ch [0] .move1-> casster_info.caster(这是问题)

输出有2例(尝试):

在小队的构造函数中:如果使用

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

在第一种情况下,我想这可能是因为我没有超载运算符=,因此仅复制地址。我试图超载它,但它引起了更多问题。(例如使用builder.build())

在第二种情况下,我希望它第一个调用复制构造函数,触发setMove1(),它调用setCaster()。如图所示,将MOVE1克隆到克隆中,但是我不明白为什么施法者未正确更新。(虽然是调用运算符=在约束后,地址应保持不变。)

以下代码应重现问题:

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;
}

如前所述,我有一个解决方法可以实现我的目标:

通过创建另一种方法,该方法通过小队中的数组迭代,并调用每个字符的setCaster()方法。

void Squad::SetCaster() {
    for (int i = 0; i < SQUAD_SIZE; i++) {
        characters_[i].SetCaster();
    }
}

但我认为这很脏

我想我发现了问题,如下所示:

问题在

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

确实如下:

  1. 创建一个字符,通过调用字符的约束,该对象在地址A. setMove1()被调用,setCaster()被调用。cast_info中的指针正确指向一个。

  2. 将对象分配给字符_ [i],其地址在地址B处,因为在创建小队时分配了字符的地址。因为我没有超载字符:: operator =,指针仍指向地址

  3. 构造函数完成,小队返回。

这是原因

std::cout << "squad.ch[0].move1->cast_info.caster: " << (squad.characters_[0].move1_->cast_info.caster) << std::endl;

显示了第三个地址(地址a),该地址既不是&amp;(artem [0])(地址b)和&amp; ch1(原始字符的地址)

解决方案要么是超载运算符=或将我的"解决方法"放在for循环之后的构造函数中。

如果有任何问题,请纠正我,或者有更好的解决方案。