Здравствуйте, MasterZiv, Вы писали:
MZ>50/50 -- может оказаться, а может и не оказаться, т.е. есть и ещё MZ>какое-то решение. А 50% -- это уже хороший шанс.
вообще-то, если исхода два, то это не означает, что они равновероятны
> MZ>50/50 -- может оказаться, а может и не оказаться, т.е. есть и ещё > MZ>какое-то решение. А 50% -- это уже хороший шанс. > > вообще-то, если исхода два, то это не означает, что они равновероятны
Правда ? А я всегда считал, что равновероятны, и попадал в лучший для
меня. Вот я везунчик!
Здравствуйте, MasterZiv, Вы писали:
MZ>Тут вопрос в другом, -- нафига вообще вызывать эту функцию MZ>process(), которая неконстантная, через класс, содержащий константную ссылку ? MZ>Надо эту проблему решать, а не людей в форуме вопросами мучать.
Ну, у меня есть одно подозрение.
Пусть у нас есть некая модель (например, дерево XML DOM) и некий контроллер, владеющий этой моделью.
Наружу модель отдаётся как константная: нечего кому попало в ней ковыряться, это задача контроллера.
А дальше мы снаружи сообщаем контроллеру, что хотим что-то поковырять с его позволения и его же руками.
std::cout << controller.theModel()->fooItem()->barItem()->buzItem()->name(); // можно
controller.theModel()->fooItem()->barItem()->buzItem()->process(); // нельзя
controller.pleaseModify( controller.theModel()->fooItem()->barItem()->buzItem() ); // можно
anotherController.pleaseModify( controller.theModel()->fooItem()->barItem()->buzItem() ); // нужно дать по пальцам
Об этом я и говорил — про права доступа. Здесь нужно было провести границу "свой-чужой" с помощью private и friend, а провели границу "можно-нельзя" с помощью const.
То есть, простой выход — запихать A::process (и, видимо, многое другое) в private, и убрать ставшую ненужной константность.
Спасибо всем кто ответил. Я почитал ответы и понял, что задача сформулирована не совсем полно. Более полная формулировка такая:
Есть код:
class A {
public:
void process() {}
};
class B {
public:
B(const A* a)
: m_a(a)
{}
const A* getA() const {return m_a;}
private:
const A* m_a;
};
class C {
public:
void process() {
m_b.getA()->process(); // Ошибка! m_b.getA() возвращает const A*, а нужно A*
}
private:
std::vector<A> m_aa;
B m_b;
};
Есть ТРИ класса. Класс C владеет списком экземпляров класса A и экземпляром класса B, причём экземпляр класса B ссылается на один из экземпляров класса A из списка.
Так как класс C является владельцем, то он имеет право как угодно изменять свои экземпляры классов A и B.
Класс B должен иметь возможность доступаться до константых методов своего объекта класса A, так как ему нужна информация о его состоянии.
Класс C в функции process хочет вызвать неконстантную функцию process именно того объекта класса A на который ссылается его объект класса B.
Возможно в этом случае решение найти проще.
Глядя на эту схему возникает мысль, что возможно проблема состоит в том, что мы пытаемся использовать указатель B::m_a для двух разных целей: для получения информации об A изнутри B и для связи объекта B и A в классе C.
Хотя с другой стороны если хранить ещё один указатель или индекс или итератор, то вроде как возникает дублирование одной и той же информации.
АЕ>class A {
АЕ>private:
АЕ> void process() {}
friend class C;
АЕ>};
АЕ>
И сделать A* неконстантным в классе B — больше там константность не нужна.
А если политик доступа много (т.е. реально у тебя не три класса), то, возможно, придётся или как-то переразбивать классы, или изгаляться, или просто забить в желании переложить ответственность за прямоту своих рук на компилятор. Быть внимательным, короче говоря
Пример переразбивания
class AforC
{
protected: // потому что для класса A это тоже можноvoid process(); // только для класса C, и больше ни для когоfriend class C;
};
class AforD
{
protected:
void perform();
friend class D;
};
class A: public AforC, public AforD {};
Если компоненты должны знать друг о друге и о композитном классе — то либо forward declaration и вынести все определения за объявление класса A,
class AforC
{
protected:
friend class A;
friend class AforD;
friend class C;
void process();
};
class AforD
{
protected:
friend class A;
friend class D;
void perform();
};
class A: public AforC, public AforD
{
public:
void execute() { process(); perform(); } // можно инлайнить, ибо объявления выше
};
// а эти определения вынесены из объявления классовinline void AforC::process() { static_cast<A*>(this)->perform(); }
inline void AforD::perform() { static_cast<A*>(this)->execute(); }
Либо — то же самое, но с помощью CRTP
template<class A> class AforC
{
protected:
friend class AforD;
friend class C;
void process() { static_cast<A*>(this)->perform(); }
};
template<class A> class AforD
{
protected:
friend class A;
friend class D;
void perform() { static_cast<A*>(this)->execute(); }
};
class A: public AforC<A>, public AforD<A>
{
public:
void execute() { process(); perform(); } // можно инлайнить, ибо объявления выше
};