【问题标题】:Acces violation on instance variable实例变量的访问冲突
【发布时间】:2013-08-18 06:56:58
【问题描述】:

我有两节课。一个抽象 (XmlNodeManager) 和您的具体子 XmlEnpManager。 抽象类定义为:

type
  TXmlNodeManager = class
    public
      constructor Create(aRoot: IXMLNode); virtual; abstract;
      function Size(): Integer;
   protected
      { sgy alias para strategy }
      sgyIterator: Integer;
      sgyAttributes: TStringList;
      sgyRoot: IXMLNode;
  end;

还有,子类:

type
  TXmlEnpManager = class (TXmlNodeManager)
    public
      constructor Create(aRoot: IXMLNode); override;
  end;

构造函数在子类中实现,代码如下:

constructor TXmlEnpManager.Create(aRoot: IXMLNode);
begin
  sgyIterator := 0;
  sgyRoot := aRoot;
  Self.GenerateAttribs;
end;

而 size() 方法是在父亲中实现的:

function TXmlNodeManager.Size(): Integer;
begin
  Size := sgyRoot.ChildNodes.Count;
end;

当我创建 XmlEnpManager 的实例,并将定义的 IXMLNode 作为参数传递,并发送 Size() 消息时。程序因 sgyRoot.ChildNodes.Count 上的访问冲突而失败(在执行时)。

我做下一个检查:

function TXmlNodeManager.Size(): Integer;
begin
  if (Assigned(sgyRoot)) then
    ShowMessage('Root assigned.')
  else
    ShowMessage('Root not assigned ???');
end;

显示第二个警报。我在 Delphi 中是最新的,并且怀疑接口引用是按值引用的,与对象不同。是正确的 ?。 如何解决这个问题?有什么想法吗?。

编辑:我做向下转换。我有一个 XmlNodeManager 类型的变量,它使用 XmlNodeManager 的子类进行初始化。这是对的 ?。示例:

// aNode can be a instance of TXmlEnpManager or another subclass of TXmlNodeManager.
procedure TXmlFileManager.SetCurrentNode(aNode: TXmlNodeManager);
    begin
      // xmCurrentNode is of TXmlNodeManager type
      xmCurrentNode := aNode;
    end;

【问题讨论】:

  • 我仍然建议您在构造函数中进行相同的检查,if Assigned(aRoot) ..,或者“GenerateAttribs”可能正在覆盖接口。
  • @SertacAkyuz 是的,已分配。抱歉,我不解释 GenerateAttribs 是做什么的,这个方法创建一个 TListString,不再赘述。
  • @ramiromd:显示调用TXmlEnpManager.Create()的代码。鉴于您显示的代码,调用者可能会将 nil IXMLNode 传递给 Create(),无论如何您都应该在 Size() 中检查:if Assigned(sgyRoot) then Result := sgyRoot.ChildNodes.Count else Result := 0;
  • Debug it. 关注数据。确认您调用了您认为正在调用的构造函数。然后确认构造函数接收到你认为的接口。最后,确认您调用Size 的对象与您之前调用构造函数得到的对象相同。调试器可以帮助您完成每个步骤。
  • 如果你不能自己调试,而且如果你只是尝试调试看起来很简单,那么你需要提供一个 SSCCE。

标签: delphi interface reference


【解决方案1】:

如果我没记错的话,你应该从你的构造函数中调用继承的构造函数:

constructor TXmlEnpManager.Create(aRoot: IXMLNode);
begin
  INHERITED Create;
  sgyIterator := 0;
  sgyRoot := aRoot;
  Self.GenerateAttribs;
end;

【讨论】:

  • 继承的构造函数是抽象的,因此编译器将简单地忽略您添加的代码。编译器将发出与问题中的源代码相同的目标代码。
  • 更糟糕的是,它会导致一个抽象错误,如果它会编译(继承的构造函数签名不同)。
  • 你错了。继承的构造函数是抽象的,所以忽略调用它显然不是问题的原因。但是,没有继承调用确实表明该类的设计不佳。构造函数可能没有理由是虚拟的,更不用说抽象了。一个类应该始终负责初始化它自己的字段,因此基类应该是分配sgyRootsgyIteratorsgyAttributes 的对象。如果有什么东西应该是抽象的,那就是GenerateAttribs,它应该填充,而不是分配,sgyAttributes。尽管如此,这并不能回答问题。
  • 你确定吗?我知道它不会调用直接父级的构造函数(它没有无参数构造函数),但我希望它调用 TObject.Create 并因此将对象的所有内存清除为零。
  • TObject.Create 什么都不做。它是 NewInstance 将对象初始化为零。既然你知道这个答案是错误的,我不明白你为什么不删除它。留下不准确的答案对社区没有帮助。
猜你喜欢
  • 2019-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多