C ++中与Matlab类属性的抽象相当的内容

4

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

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

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


详细说明:
我需要将很多面向对象的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属性值。
  • 抽象属性不能定义设置或获取访问方法(请参见属性访问方法),也不能指定初始值。定义具体属性的子类可以创建设置或获取访问方法并指定初始值。
那么,在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 关键字的方式?


2
至少根据您的描述,我认为Matlab属性已经够混乱了(如果您愿意,可以将其解读为“对C ++足够陌生”),因此任何转换为C ++的代码都会做以下两件事情之一:要么大量更改代码,要么最终成为相当差(或者至少是奇怪的)C ++代码。 - Jerry Coffin
1
抽象关键字的定义来自MathWorks网站。此外,我认为在C++中使用Dependent关键字获得的行为并不奇怪。它确保只有在需要时才计算属性A,并确保在使用时始终更新。还要考虑到我可能误解了Matlab中Dependent的含义 :) - Alessandro L.
注意:子类无法访问Foo的私有成员A。 - Philipp
1
让我举一个例子来说明我的意思。C++使得在需要时计算一个值变得容易--没有问题。在基类中声明这将在所有派生类中发生--抱歉,但我不知道有什么方法可以做到这一点。话虽如此,在C++中告诉用户他们将是最新的价值相当于告诉某人你给他们的水会是湿的。除非另有规定,否则每个人都会认为是这种情况。 - Jerry Coffin
1
好的,Dependent是一个可以简单复制的行为。那抽象类呢? - Alessandro L.
1个回答

2
首先,我认为重要的是问:一个类的公共接口是什么(它的职责是什么,如何与其他对象交互)?
从你的Matlab代码来看,答案是:该类定义了属性A和B以及方法computeA。根据我对Dependent属性的理解,我怀疑computeA()应该不是公共的(请参见Matlab文档)。如果你的代码需要这个方法,当然可以将其保留为公共的,但我建议尽量减少其可访问性。
现在,在C++中不存在属性的概念。有趣的是,Matlab的基类决定了是否存在A.get、A.set或两者都有,以及可访问性。我不知道背后的原因,但在我看来似乎没有太多意义。在C++中,我会将属性转换为get/set方法。请参见这个问题,了解如何在C++中实现这些方法。根据您的选择,可以将非Dependent属性实现为成员对象或get/set方法。
一旦您定义了方法的公共接口,就可以开始考虑如何实现它。请注意,Matlab和C++的内存管理不同(Matlab使用写时复制,并关注内存管理,而纯C++中没有这些)。此外,在(缓慢的面向对象)Matlab代码中,可能需要缓存值(就像computeA和Dependent属性一样),但在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存储在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)引用还是值传递...


1
我仔细阅读了这篇文章,看起来你提出的建议都很好,解决了我大部分的疑惑。感谢你的时间 :) - Alessandro L.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接