4

简短版本:
考虑以下伪代码:

class Foo {
    private:
        abstract type myVar;
} // This class is abstract

您将如何在标准 C++ 中实现这种行为?


长版:
我必须将大量面向 Obj 的代码从 Matlab 移植到 C++。请注意,我是世界上使用 Matlab 经验最少的人,自 2007 年以来我就不再使用 C++。

我在这个主题上搜索了很多,但我找不到我的问题的正确答案。所以我在这里:)

假设你有这个 matlab 类:

classdef Foo < handle
    properties (Abstract, Dependent)
        A
    end

    properties
        B
    end

    methods (Abstract)
        computeA()
    end

    methods (Access = protected)
        function obj = Foo(bar)
            obj.B = Matlab.BlaBlaBla(bar)
    end
end

这个类(我想)不能“直接”分配,因为它的构造函数受到保护。属性“A”也是抽象的(暂时忽略也是依赖的事实)。MathWorks 告诉我们,这意味着:

  • 具体的子类必须重新定义没有 Abstract 属性的抽象属性,并且必须使用与抽象超类中使用的相同的 SetAccess 和 GetAccess 属性值。
  • 抽象属性不能定义 set 或 get 访问方法(请参阅属性访问方法),也不能指定初始值。定义具体属性的子类可以创建 set 或 get 访问方法并指定初始值。

那么你将如何在 C++ 中正确地翻译这种行为呢?如果我按照以下方式进行操作是否正确?(我的意思是这不是一个糟糕的设计实践)

class Foo {
    private:
         type A;
         type B;
    protected:
         virtual void computeA() = 0;
         Foo(type bar) { this.B = SomeFoo(bar); }
}

我认为(我可能是错的)是,如果我这样做,就必须这样做

class Subclass: Foo {
    protected:
        void computeA(){...} 
    public:
        type A() { computeA(); return A; } //This is A getter that grants Dependent behavior
}

否则在编译时会出错。

我错了吗?有更好的方法吗?也是翻译 Dependent 关键字的正确方法吗?

4

1 回答 1

2

首先,我认为重要的是要问:一个类的公共接口是什么(它的职责是什么,它如何与其他人交互)?

从您的 Matlab 代码中,答案是:该类定义了属性 A 和 B 以及方法 computeA。根据我对 Dependent 属性的理解,我怀疑 computeA() 应该是公开的(参见Matlab 文档)。如果您的其余代码需要这个,当然您可以将其公开,但我会尽量减少可访问性。

现在 C++ 中不存在属性的概念。Matlab 的有趣之处在于基类决定是否存在 A.get、A.set 或两者以及可访问性。我不知道这背后的原因,但在我看来这似乎没有太大意义。在 C++ 中,我会将属性转换为获取/设置方法。有关在 C++ 中实现这些的讨论,请参阅此问题。根据您的选择,您可以将非依赖属性实现为成员对象或 get/set 方法。

一旦您定义了方法的公共接口,我就会尝试开始考虑如何实现它。请注意,Matlab 和 C++ 的内存管理是不同的(Matlab 使用 Copy on Write 并关心内存管理,这在纯 C++ 中都不存在)。此外,在(慢速面向对象的)Matlab 代码中可能需要缓存值(如使用 computeA 和相关属性所做的那样),但在 C++ 中则不一定。为了避免过早的优化,为什么不这样做:

class Foo {
    public:
      ClassB B;
      virtual ClassA getA() = 0;
      //define a setA()=0 if you need it here
    protected:
         //I wouldn't force subclasses to have the "caching" of dependent properties, so no virtual void computeA() = 0; 
         Foo(ClassBar const& bar) { this.B = ClassB(bar); /*Note that SomeFoo cannot be assigned to B*/ }
}
class Subclass: public Foo {
    private:
        ClassA A;
    public:
        ClassA getA() { ClassA A; /*compute A*/ return A; } 
}

如果你体验到 A 的计算速度太慢,你仍然可以在 Subclass 中“本地缓存 A”:

class Subclass: public Foo {
    private:
        ClassA A;
    public:
        ClassA getA() { /*compute A if required*/ return A; } 
}

如果您真的想将 A 存储在 Foo 中,我宁愿将其实现为

class Foo {
    private:
      ClassA A;
    public:
      ClassB B;
      ClassA getA() { if (!A.initialized) A=computeA(); return A; };
    protected:
         virtual ClassA computeA() = 0;
         Foo(ClassBar const& bar) { this.B = ClassB(bar); /*Note that SomeFoo cannot be assigned to B*/ }
}
class Subclass: public Foo {
    protected:             
         virtual ClassA computeA() {...}
}

并且不要忘记始终考虑您是否真的想通过(const)引用或值传递......

于 2013-01-16T15:10:49.983 回答