对于类属性,C ++相当于Matlab Abstract

时间:2013-01-16 13:14:48

标签: c++ matlab porting abstract

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

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”也是抽象(暂时忽略了也是Dependent的事实)。 MathWorks告诉我们,这意味着:

  • 具体的子类必须在没有的情况下重新定义抽象属性 抽象属性,必须使用相同的值为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关键字的正确方法吗?

1 个答案:

答案 0 :(得分:2)

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

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

现在C ++中不存在属性的概念。关于Matlab的有趣之处在于基类决定是否存在A.get,A.set或两者以及可访问性。我不知道背后的理由,但在我眼里似乎并没有多大意义。在C ++中,我会将属性转换为get / set方法。有关在C ++中实现这些内容的讨论,请参阅this question。根据您的选择,您可以将非依赖属性实现为成员对象或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的计算速度太慢,您仍然可以在子类中“本地缓存A”:

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

如果你真的想在A中存储A,我宁愿把它实现为

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)引用或值...