将方法调用限制为另一个方法

Restricting method call to another method

提问人:Luchian Grigore 提问时间:8/31/2011 最后编辑:Luchian Grigore 更新时间:6/26/2012 访问量:143

问:

对此可能有一个相当简单和直接的答案,但由于某种原因我看不到它。 我需要将类中的调用方法限制为仅由某些接口的派生类实现的某些方法。

说我有

class A{
    public:
        static void foo();
};

class myInterface{
    public:
        virtual void onlyCallFooFromHere() = 0;
}

class myImplementation : public myInterface{
    public:
        virtual void onlyCallFooFromHere()
        {
            A::foo(); //this should work
        }
        void otherFoo()
        {
            A::foo(); //i want to get a compilation error here
        }

}

所以我应该只能从方法调用A::fooonlyCallFooFromHere()

有没有办法实现这一目标?我愿意接受任何建议,包括更改课程设计。

编辑:

所以。。。我觉得有必要进一步解释这个问题。我有一个与数据库交互的实用程序类(主要是更新记录) - 类 A。 在我的接口(表示一个基本的数据库对象)中,我有虚函数 updateRecord(),我从中调用 db 实用程序类的方法。我只想在所有扩展类的 updateRecord() 函数中强制更新数据库,而不是在其他任何地方。我不认为这是一个糟糕的设计选择,即使不可能。但是,如果确实不可能,我将不胜感激不同的解决方案。

C++ OOP 设计模式

评论

4赞 Cat Plus Plus 8/31/2011
你为什么需要它?似乎是一个糟糕的设计。您可以将成员设为私密并使用好友,但好友关系是全班的,您不能只允许一个成员呼叫它,而不允许另一个成员不呼叫它。AmyImpl
3赞 Nawaz 8/31/2011
为什么需要这么奇怪的类设计?
0赞 Luchian Grigore 8/31/2011
这和朋友上课一样糟糕......我只想将私有/受保护的方法限制为其他方法而不是类。我可以扩展为什么我需要这个,但对于我正在寻找的答案没有区别......
0赞 Nawaz 8/31/2011
@Luchian:我还在想,为什么世界上只有C++程序员需要这样的类设计?也许,他们想得太多了?
0赞 Luchian Grigore 8/31/2011
我稍微扩展了这个问题以提供一些进一步的信息,希望它现在更有意义......

答:

0赞 Kerrek SB 8/31/2011 #1

您可以将项目拆分为不同的 TU:

// A.h
class A
{
public:
    static void foo();
};


// My.h
class myInterface
{
public:
    virtual void onlyCallFooFromHere() = 0;
}

class myImplementation : public myInterface
{
public:
    virtual void onlyCallFooFromHere();
    void otherFoo();
};


// My-with-A.cpp
#include "My.h"
#include "A.h"

void myImplementation::onlyCallFooFromHere() { /* use A */ }


// My-without-A.cpp
#include "My.h"

void myImplementation::otherFoo() { /* no A here */ }

评论

0赞 Nawaz 8/31/2011
这个解决方案是这样的:使用限定名称工作;和不合格的名称不起作用。aspace::A::f()
0赞 Kerrek SB 8/31/2011
我从来没有声称它很漂亮,或者设计有意义:-)
0赞 Kerrek SB 8/31/2011
此外,如果你真的想要,你可以从你的外部雇佣团队中物理地隐瞒文件(及其超级秘密的素因分解量子算法?)......我的意思是,它仍然没有意义,但有时探索很有趣......A.honlyCallFooFromHere()
0赞 Ed Heal 8/31/2011
Kerrek SB - 我同意 - 麻烦在于没有意义的设计 - 一些可怜的人必须在维护阶段弄清楚。C++ 为您提供了充足的绳索来悬挂自己 - 如果您选择这样做!
3赞 Ed Heal 8/31/2011 #2

改变班级设计 - 你想要的是不可能的。

我不确定你想用这么少的细节实现什么,我无法进一步评论。

评论

0赞 Luchian Grigore 8/31/2011
这更适合作为评论。
2赞 Nawaz 8/31/2011
@Luchian:如果他认为你想要的是不可能的,那么这就是一个答案。+1
0赞 John Humphreys 8/31/2011 #3

您可能知道这一点,但通过继承,您可以拥有公共、受保护和私有成员访问权限。

如果成员在基类中是私有的,则派生无法访问它,而如果同一成员受到保护,则派生类可以访问它(虽然它仍然不是公共的,因此您正在维护封装)。

但是,没有办法阻止特定函数能够查看其范围内可用的内容(这是您要问的),但您可以设计基类,以便派生类只能访问它的特定元素。

这可能很有用,因为类 B 可以从受保护的类 A 继承(从而获得其受保护的成员),而类 C 可以从与公共类相同的类 A 继承(因此无法访问其受保护的成员)。这将使你至少获得某种形式的调用可用性差异 - 但是在类之间,而不是在同一类中的函数之间。

评论

0赞 Lambdageek 8/31/2011
你的想法是行不通的。如果继承自 ,它将能够访问 的 protected 成员。无论是公开继承、保护继承还是私下继承,都只影响那些使用或派生自 ,而不是自身的实现。CAACACC
0赞 Tom Kerr 8/31/2011 #4

这可能有效。

class myInterface;

class A {
    private:
        friend class myInterface;
        static void foo();
};

class myInterface {
    public:
        virtual void onlyCallFooFromHere() {callFoo();}
    protected:
        void callFoo() {A::foo();}
};

虽然在这一点上,我想我只是将 A::foo 设为 myInterface 的静态。这些担忧不再是分开的。

class myInterface {
    protected:
        static void foo();
};

foo 在 A 中有什么原因吗?

1赞 Lambdageek 8/31/2011 #5

[免责声明:此解决方案将阻止墨菲,而不是马基雅维利。

怎么样:

class DatabaseQueryInterface {
public:
  ~virtual DatabseQueryInterface() = 0;
  virtual Query compileQuery() const = 0; // or whatever
  virtual ResultSet runQuery(const Query&) const = 0; // etc
};

class DatabaseUpdateInterface : public DatabaseQueryInterface {
public:
   virtual Update compileUpdate() const = 0; // whatever
};

class DatabaseObject {
public:
  virtual ~DatabaseObject() = 0;
protected:
  virtual void queryRecord(const DatabaseQueryInterface& interface) = 0;
  virtual void updateRecord(const DatabaseUpdateInterface& interface) = 0;
};

class SomeConcreteDatabaseObject : public DatabaseObject {
  protected:
     virtual void updateRecord(const DatabaseUpdateInterface& interface) {
        // gets to use interface->compileUpdate()
     }

     virtual void queryRecord(const DatabaseQueryInterface& interface) {
        // only gets query methods, no updates
     }
};

因此,基本思想是,基类会释放一个私有对象和一个私有对象,当需要调用子类的受保护成员时,它会将接给方法,并将接给方法。DatabaseObjectQueryUpdateUpdateupdateRecord()QueryqueryRecord()

这样一来,子类的自然做法就是使用它们传递的对象来与数据库通信。当然,他们总是可以诉诸肮脏的伎俩来存储传入的对象,并尝试稍后从查询方法使用它,但坦率地说,如果他们走得太远,他们就只能靠自己了。Update