matlab oop中的私有构造函数

时间:2015-04-16 10:05:59

标签: matlab oop

Matlab不允许定义不同的方法来定义具有不同参数列表的多个构造函数,例如这不起作用:

classdef MyClass

    methods
        function [this] = MyClass()
            % public constructor
            ...
        end        
    end    
    methods (Access = private)
        function [this] = MyClass(i)
            % private constructor
            ...
        end
    end

end

但是,如上例所示,有一些私有构造函数有时很有用,这些构造函数具有无法从公共接口调用的特定语法。

如果您需要定义公共和私有构造函数,您将如何最好地处理这种情况?

检查调用堆栈???

classdef MyClass
    methods
        function [this] = MyClass(i)
            if (nargin == 0)
                 % public constructor
                 ...
            else
                 % private constructor
                 checkCalledFromMyClass();
                 ...
            end
        end
    end
    methods(Static=true, Access=Private)
        function [] = checkCalledFromMyClass()
           ... here throw an error if the call stack does not contain reference to `MyClass` methods ...
        end
    end
end

定义帮助程序基类???

% Helper class 
classdef MyClassBase
    methods (Access = ?MyClass)
       function MyClassBase(i)
       end
    end
end

% Real class
classdef MyClass < MyClassBase
    methods
       function [this] = MyClass()
           this = this@MyClassBase();
       end
    end
    methods (Static)
       function [obj] = BuildSpecial()
           obj = MyClassBase(42); %%% NB: Here returned object is not of the correct type :( ...
       end
    end
end

其他解决方案???

3 个答案:

答案 0 :(得分:2)

通过利用varargin

,您可以拥有一个接受多种语法的构造函数
classdef MyClass

    methods (Access = public)
        function obj = MyClass(varargin)
            % Do whatever you want with varargin
        end        
    end 

end

您可能更常见的是,所有语法都需要一些输入,然后还有一些可选输入:

classdef MyClass

    methods (Access = public)
        function obj = MyClass(reqInput1, reqInput2, varargin)
            % Do whatever you want with varargin
        end        
    end 

end

如果你想对事物的构造方式有更多的控制,我会有一个构造函数,然后还有一些调用构造函数的公共静态方法。

例如,让我们说我希望能够通过直接提供参数或通过提供包含参数的配置文件的名称来构造对象:

classdef MyClass

    methods (Access = public)
        function obj = MyClass(reqInput1, reqInput2, varargin)
            % Do whatever you want with varargin
        end        
    end 

    methods (Static, Access = public)
        function obj = fromFile(filename)
             myparams = readmyconfigfile(filename);
             obj = MyClass(myparams.reqInput1, myparams.reqInput2, ...);
        end
    end

end

然后,您可以使用o = MyClass(inputs)o = MyClass.fromFile(filename)创建对象。

如果您想允许人们从配置文件中构造 ,那么您可以将构造函数设为私有。如果你想以其他方式调用构造函数,你可以添加额外的公共静态方法。

在任何情况下,重点是拥有一个接受多种语法的构造函数的惯用方法是利用varargin

答案 1 :(得分:2)

我曾经尝试解决此限制的一个偷偷摸摸的技巧是使用另一个只能由MyClass构造的'tag'类,然后使用它来计算出你需要的构造函数变体。这是一个简单的草图:

classdef MyClass
    properties
        Info
    end
    methods
        function o = MyClass(varargin)
            if nargin == 2 && ...
                       isa(varargin{1}, 'MyTag') && ...
                       isnumeric(varargin{2}) && ...
                       isscalar(varargin{2})
                o.Info = sprintf('Private constructor tag: %d', varargin{2});
            else
                o.Info = sprintf('Public constructor with %d args.', nargin);
            end
        end
    end
    methods (Static)
        function o = build()
        % Call the 'private' constructor
            o = MyClass(MyTag(), 3);
        end
    end
end

classdef MyTag
    methods (Access = ?MyClass)
        function o = MyTag()
        end
    end
end

请注意Access = ?MyClass说明符,这意味着只有MyClass才能构建MyTag的实例。还有更多关于在doc:http://www.mathworks.com/help/matlab/matlab_oop/method-attributes.html

中使用这种方法属性的内容

答案 2 :(得分:1)

我很想在你的第一个选项上进行修改,但要修改构造函数以获得一个未记录的&#34;模式&#34;而不仅仅是任何输入arg。

在下面的示例中,我提供了该名称**private**,但您可以拥有任何您希望最终用户不会偶然发现的内容......

要加倍确定你仍然可以检查堆栈。

    function [this] = MyClass(i)
        if (nargin == 0)
             % public constructor
        else
             % private constructor
             if ischar ( i ) && strcmp ( i, '**private**' )
                 this.checkCalledFromMyClass();
             else
                 error ( 'MyClass:Consturctor', 'Error calling MyClass' );
             end
        end
    end
end