Ограничение вызова метода другим методом - PullRequest
1 голос
/ 30 августа 2011

Вероятно, есть довольно простой и прямой ответ на этот вопрос, но по какой-то причине я его не вижу.Мне нужно ограничить вызов методов из класса только некоторыми методами, реализованными производными классами некоторого интерфейса.

Скажем, у меня есть

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::fooиз метода onlyCallFooFromHere()

Есть ли способ добиться этого?Я открыт для любых предложений, в том числе для изменения дизайна класса.

РЕДАКТИРОВАТЬ:

Итак ... Я чувствую, что есть необходимость более подробно объяснить проблему.У меня есть служебный класс, который взаимодействует с базой данных (в основном, обновляет записи) - класс А. В моем интерфейсе (который представляет собой основные объекты базы данных) у меня есть виртуальная функция updateRecord (), из которой я вызываю методы из служебного класса db.Я хочу принудительно обновлять базу данных только в функции updateRecord () всех расширяющихся классов и нигде больше.Я не верю, что это плохой выбор дизайна, даже если это невозможно.Однако, если это действительно невозможно, я был бы признателен за другое решение.

Ответы [ 5 ]

3 голосов
/ 30 августа 2011

Изменить дизайн класса - то, что вы хотите, невозможно.

Я не уверен в том, чего вы пытаетесь достичь с таким небольшим количеством деталей, и я не могу комментировать дальше.

1 голос
/ 30 августа 2011

[Отказ от ответственности: это решение остановит Мерфи, а не Маккиавелли.]

Как насчет:

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
     }
};

Итак, основная идея заключается в том, что ваш DatabaseObject базовый класс сжимается от частногоQuery объект и частный Update объект, и когда приходит время вызывать защищенные члены подкласса, он передает интерфейс Update методу updateRecord() и интерфейс Query к queryRecord()method.

Таким образом, для подклассов естественным является использование объекта, который они передают, для связи с базой данных.Конечно, они всегда могут прибегнуть к грязным уловкам, чтобы сохранить переданный объект Update и попытаться использовать его позже из метода запроса, но, честно говоря, если они пойдут на такую ​​длину, они сами по себе.

0 голосов
/ 30 августа 2011

Это может сработать.

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?

0 голосов
/ 30 августа 2011

Вы, вероятно, знаете это, но с наследованием вы можете иметь открытый, защищенный и закрытый доступ к членам.

Если член является закрытым в базовом классе, производный не может получить к нему доступ, тогда как если тот же член защищен, то производный класс может получить к нему доступ (хотя он все еще не является общедоступным, поэтому вы поддерживаете инкапсуляцию) .

Нет способа помешать определенным функциям видеть то, что доступно в их области (хотя это то, о чем вы спрашиваете), но вы можете спроектировать свой базовый класс так, чтобы производные классы могли получать доступ только к определенным его элементам. .

Это может быть полезно, поскольку класс B может наследовать от класса A как защищенный (таким образом получая свои защищенные члены), в то время как класс C может наследовать от того же класса A, что и public (таким образом, не получая доступ к своим защищенным членам). Это позволит вам по крайней мере получить некоторую форму различий в доступности вызовов - хотя между классами, а не между функциями в одном классе.

0 голосов
/ 30 августа 2011

Вы можете разбить свой проект на разные 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 */ }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...