从C++和Java到Ada的类配方概念

Reg*_*ego 5 c++ java algorithm ada

也许C++和Java人员可以帮助我定义我将要解释的这个问题.关于如何表示实现动态标识符的三个主要分支的类的构造函数,我在Ada(你不需要知道它,我只是对这个概念感兴趣)有一个问题:

  • 纯数值(int,float,String,等等)
  • 列表/堆栈项目
  • C++中的东西很可能是一个线程(在Ada中我们有一个更广泛的概念,与任务相关,但我们可以将一个简单的任务概念作为一个线程,所以这个概念也适用)

我要调用这个类Par_Class,并且是任何构造的对象调用Par_Obj.因此,当Par_Obj创建一个对象时(因此,数值被初始化,列表/堆栈分配了其他列表/堆栈或为空并且保留了线程执行的内存范围),OS自动开始执行新线程与我的主应用程序并行(现在他们争夺系统资源).但是为了简化示例,让我们假设我有一个带有整数的类和一个指向字符串的指针.

例如,在C++中,我可以编写代码(如果我做错了,请纠正我)

class Par_Class {
public:
  Par_Class (int aValue, const std::string & aName);

private:
  int theValue;
  std::string theName;
};
Run Code Online (Sandbox Code Playgroud)

构造函数可以实现为

Par_Class::Par_Class (int aValue, const std::string & aName)
  : theValue(aValue)
  , theName(aName)
{
}
Run Code Online (Sandbox Code Playgroud)

最后我们可以实例化这个类

Par_Class Par_Obj (23, "My object is this");
Run Code Online (Sandbox Code Playgroud)

并确保此构造方法属于Par_Class类,而不属于任何其他类.

同样,在Java中,我们可以编码

public class Par_Class {
  private int theValue;
  private String theName;

  public Par_Class (int aValue, String aName){
    theValue = aValue;
    theName = aName;
  }
};
Run Code Online (Sandbox Code Playgroud)

我们可以使用实例化对象

Par_Class Par_Obj = new Par_Class (23, "My object is this");
Run Code Online (Sandbox Code Playgroud)

(如果我错了,请再次纠正我).同样,Par_Class构造函数是类的方法Par_Class.

在Ada 2005中,这个类可以编码为

--par_pkg.ads
package Par_Pkg is
   type Par_Class is tagged private;
   type Par_Class_Ptr is access all Par_Class;
   type Integer_Ptr is access Integer;

   function Construct 
     (P : access Par_Class; aValue : Integer; aName : Integer_Ptr)
      return Par_Class_Ptr;

private
   type Par_Class is tagged
      record
         theValue : Integer;
         theName  : Integer_Ptr;
      end record;
end Par_Pkg;

-- par_pkg.adb
package body Par_Pkg is
   function Construct 
     (P : access Par_Class; aValue : Integer; aName : Integer_Ptr)
      return Par_Class_Ptr is
      pragma Unreferenced (P);
      P_Ptr : constant Par_Class_Ptr := new Par_Class;
   begin
      P_Ptr.theValue := aValue;
      P_Ptr.theName := aName;
      return P_Ptr;
   end Construct;

end Par_Pkg;
Run Code Online (Sandbox Code Playgroud)

并且用户可以打电话

with Par_Pkg; use Par_Pkg;
procedure Par_Main is
   Par_Obj : Par_Class_Ptr;
   Int_Obj : Integer_Ptr;
begin
   Int_Obj := new Integer;
   Int_Obj.all := 12; -- don't worry about been string or integer
   Par_Obj := Par_Obj.Construct 
     (aValue => 23,
      aName => Int_Obj);
end Par_Main;
Run Code Online (Sandbox Code Playgroud)

这就是问题所在.编译器告诉我,我无法使用Construct方法,Par_Obj := Par_Obj.Construct因为我的对象是null.但它是如此明显,因为我想要做的就是初始化对象(所以它不再是null).还有其他构造对象的方法,例如,使用类外部的函数,但我不想使用这种方法,因为它远离架构.你能帮我把问题告诉我的Ada朋友,这样他们可以帮我在Ada中实现吗?我想我在一般概念术语中解释这个问题有点困难.谢谢.

回答

@paercebal给了我我认为可以实现我的目标:

  • "有没有办法在Par_Class中声明一个"静态"函数?" 并且"有没有办法让非成员函数声明为Par_Class的朋友?"

我可以用"有没有办法在标记类型中声明一个"静态"函数来完成它?另外,声明类的包可以充当朋友还是静态函数?"

更新

根据@SimonWright和comp.lang.ada论坛的一些人的建议,为什么实现它有一些更好的理由:

function Construct (aValue: Integer; aName: Integer)
                    return Par_Class is
begin
  return (theValue => aValue,
          theName  => aName);
end Construct;
Run Code Online (Sandbox Code Playgroud)

所以我问:在这种情况下,函数Construct会表现为C++静态函数(或者可能是朋友吗?)?

德米特里卡扎科夫回答说:

这取决于你的意思.在阿达:

  1. 没有隐藏的参数

  2. 操作可以在参数和/或结果的任何组合中调度(虚拟).但是操作不能在多种类型中调度(没有多次调度).调度参数的所有标签必须相同(没有多方法).

  3. 由于可见性规则基于包,因此没有静态或朋友操作.

上面的函数Construct是一个原始操作,它不是构造函数.

Ada中的构造函数是隐含的,它们由

  1. 组件的构造(以未指定的顺序,递归地);

  2. 如果类型是Ada.Finalization的后代,则调用Initialize.[Limited_]受控制.(不会调用重写的Initialize主体!即Ada构造函数不会遍历派生路径.简而言之,聚合是安全的,派生不是;

  3. 启动所有任务组件.(注意,调用Initialize时任务没有运行!)

析构函数按相反顺序执行:tasks - Finalize - components.

我猜它会回应.谢谢大家

pae*_*bal 2

关于 Ada 构造函数?

很难解释这个概念,因为我不了解 Ada 语言的哲学、局限性和优势。不过,猜测 Ada 中没有构造函数。

(非友元?)非成员函数?

我猜这不是你想要的解决方案:

  • 有一个Initialize成员函数Par_Class,它设置 的私有数据Par_Class
  • 有一个Par_Class_Constructor非成员函数调用该初始化函数

但这个解决方案并不令人满意,因为它会公开Initialize为公共方法,这违反了封装性(任何人都可以随时调用该方法,这几乎与公开所有数据一样愚蠢)。

静态成员函数?

您想要做的是仅使用一个函数调用来分配和初始化您的代码,而不破坏封装

你觉得(正确地)这个函数应该是Par_Classinterface的一部分,因此,你想Par_Class' 声明中声明它(这将产生一个有趣的副作用,即让它访问Par_Class私有成员变量)

在 Java 或 C++ 中,除了构造函数之外,可以通过使用静态方法(即类的方法,而不是实例的方法)来解决此问题。此方法是static,因此无法访问this意味着您可以在不需要 的实例的情况下调用它Par_Class

所以,你对 Ada 朋友的问题可能是:有没有办法在内部声明一个“静态”函数Par_Class

(朋友?)非成员函数?

另一种具有类似效果的方法(如果不是类似的语法糖)是使用非成员函数来实现这一目的。在 C 中,您将拥有类似: 的函数,该函数返回指向Par_Class 类型的Par_Class_Constructor指针。struct

在 C++ 中,您可以使用与 Java 相同的技巧,或者与 C 相同的技巧。在最后一种情况下,Par_Class_Constructor将声明类friendPar_Class访问其私有数据,或者可以调用有权访问该私有数据的初始化成员方法私人数据。

这样,您仍然可以用一个函数分配和初始化您的对象,并且仍然保护您的类的封装(因为此方法返回一个新对象,而不是像Initialize上面描述的不令人满意的方法那样修改它)

因此,如果拥有一个非成员函数对您来说没问题,另一种可能性可能是:有没有办法声明一个非成员函数?friendPar_Class

编辑

注意:我之前的题外话答案……我真的应该去睡觉了……

我不认识 Ada,但阅读你的代码:

with Par_Pkg; use Par_Pkg;
procedure Par_Main is
   Par_Obj : Par_Class_Ptr;
   Int_Obj : Integer_Ptr;
begin
   Int_Obj := new Integer;
   Int_Obj.all := 12; -- don t worry about been string or integer
   Par_Obj := Par_Obj.Construct 
     (aValue => 23,
      aName => Int_Obj);
end Par_Main;
Run Code Online (Sandbox Code Playgroud)

我看到 Int_Obj 已经用new Integer语句分配了。

您不需要以同样的方式分配 Par_Obj 吗?

像这样的东西(我从你的整数初始化代码推断):

   Par_Obj := new Par_Class_Ptr      -- allocate ?
   Par_Obj.all := Par_Obj.Construct  -- initialize ?
     (aValue => 23,
      aName => Int_Obj);
Run Code Online (Sandbox Code Playgroud)

???