Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/147.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 我可以禁止在对象实例上调用静态方法吗?_C++_Factory - Fatal编程技术网

C++ 我可以禁止在对象实例上调用静态方法吗?

C++ 我可以禁止在对象实例上调用静态方法吗?,c++,factory,C++,Factory,我有很多转换函数的类: class Something { public: string toXml(); string toJson(); ... static Something fromXml(string); // factory static Something fromJson(string); // factory ... }; 因为静态函数可以在实例上调用, 编写这样的代码很容易: Something sss; ...

我有很多转换函数的类:

class Something {
  public:

    string toXml();
    string toJson();
    ...

    static Something fromXml(string);  // factory
    static Something fromJson(string); // factory
    ...
};
因为静态函数可以在实例上调用, 编写这样的代码很容易:

Something sss;

... initializing sss ...

string xml1 = sss.toXml();
sss.fromXml(xml1); // does nothing
string xml2 = sss.toXml();
assert(xml1 == xml2); // always true
所以我想禁止从XXX调用对象,或者 至少让他们做些不同的事情


有什么方法可以做到这一点吗?

请修改您的设计。将静态方法拆分为单独的SomethingFactory类。这简直令人困惑

他们真的需要成为班级成员吗?防止这种情况的明显方法是使它们具有自由函数。

该标准实际上要求所有兼容的编译器在9.4[class.static]/2中允许这种语法:

类X的静态成员s可以是 指使用限定id 表达式X::s;没有必要 使用类成员访问语法的步骤 (5.2.5)指静态构件。A. 静态成员可能指使用 中的类成员访问语法 对象表达式是哪种情况 评估

现在,您可以做一些事情来避免陷阱,没有特定的顺序

  • 将它们转换为不允许语法的自由函数
  • 改进命名约定:
    createFromXml
    以更明确地说明它是工厂方法
  • 将静态方法转换为将在对象中执行操作的具体方法,并提供将重用代码的外部方法工厂
从设计的角度来看,第一个选项的优点是从类本身取消耦合序列化格式
Something
(更好的名称),表示具有属性、操作和所有这些OO内容的对象。但在许多情况下,某些东西与它可以被序列化以不同格式发送或存储这一事实无关


只想使用XML的
Something
类的用户甚至不需要知道对象可以序列化为Json。如果以后向类中添加数据库持久性选项,Json或XML的用户都不会受到影响。

将静态成员设置为私有如何

如果您需要具有静态的成员函数,这可能是解决此问题的一种方法


为什么有静态成员函数?他们是否需要访问课堂上的其他内容?如果没有,那么您可以让它们释放不在带有
Something
的标题中的函数,而是在单独名称空间的另一个标题中的函数。

自c++17以来,您可以使用
[[nodiscard]]]
属性:

class Something {
  public:

    ...

    static [[nodiscard]] Something fromXml(string);  // factory
    static [[nodiscard]] Something fromJson(string); // factory
    ...
};

这并不是您想要的,但可能更好。

在这一点上:讨论了自由函数如何更好地进行封装。我只是想保持全局命名空间干净-这个对象在大型程序中随处可见。当然,我可以为它们创建“SomethingUtils”名称空间。但它们看起来像“工厂”功能。在我花了2个小时搜索不存在的“bug”之前,它实际上是有意义的。无论如何,免费函数都是类的“朋友”。Incapsulation level不会改变。@Ivan:如果这是一个问题(而且是一个不错的问题),那么选择您自己的名称空间并一致地使用它,并在其中放入一些东西,这样它们仍然可以在一起。@Ivan:自由函数不一定是类的
朋友
s,它们可以依赖于现有接口(我想您可以在内存中创建具有给定状态的
对象)。还有另一个设计优势:
Something
的大多数用户可能不太关心它是否可以序列化为XML、Json或任何其他技术,但是如果这些操作是类的(静态)成员,然后,
Something
抽象正在“泄漏”如何将其序列化到系统的其余部分。这也可能是SomethingFactory名称空间。但是函数必须是类的朋友。代码将更加复杂。如果我能禁止混乱的调用语法,那就完全可以。“伊凡:如果你能重新设计C++语言,那么你的特定问题就很小了,那么你就不会有任何问题了。(这有时是最好的解决方案)但是,切换语言不太可能满足你的需求,所以你的理想解决方案在C++中是不可能的。@罗杰:我不确定C++标准直接说我不能识别使用什么调用形式。如果C++在“Objist.StaseMeod()”中调用“对象”,它可以将它提供给静态函数,如“这个”。或者做类似的事情。@Ivan:我肯定这不会提供一种方法。(“直接”?*耸耸肩*,它没有,这在这里已经足够好了。)@Ivan:不完全是这样,虽然您在代码中没有看到它,但在非静态成员函数中有一个隐藏参数,即“this”。静态成员函数的签名与自由函数的签名等效,因此
classx{Static void f();void g();};空h()void(*ptr)(=X::f
ptr=h
,但签名与成员函数不兼容,因此
ptr=X::g是一个错误。您的意思是希望编译器根据用法而不是定义来更改函数的类型。@David:这些函数不是用于序列化,而是用于转换。任何使用该标题的人都希望将某些内容转换为更有用的形式。它可以是JSON、XML或其他对象。将所有这些内容保存在一个标题中似乎是合理的。所以标准允许两种调用形式。但它并没有说我无法识别所使用的形式。例如,它可以在“Type::method”调用中将“this”设置为NULL,但在“object.method”调用中将其设置为real object。不过,我还是想知道为什么允许使用“object.method”语法。它令人困惑,尤其是在模板中需要的“this->staticMethod()”表单中