константность для референтных классов - PullRequest
2 голосов
/ 21 июня 2011

У меня есть пара классов, один из которых сохраняет ссылку на объект другого:

class Inner {};

class Outer {
    Inner & in;

public:
    Outer(Inner & in) : in(in) {}
};

Что если мне нужно создать объект Outer из константной ссылки на Inner? Должен ли я написать конкретный класс, скажем OuterConst, для этого?

UPD : Какие-нибудь изящные решения с использованием шаблонов? Во избежание дублирования кода в классе OuterConst.

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

Ответы [ 4 ]

6 голосов
/ 21 июня 2011

Что если мне нужно создать объект Outer из константной ссылки на Inner?

Ну, ты не можешь. Вот и все. Если Outer нужно только вызывать константные функции-члены Inner, тогда сделайте его константной ссылкой, иначе ваш класс зависит от изменяемого внутреннего объекта, и вы не должны создавать объект Outer из константной ссылки.

3 голосов
/ 21 июня 2011

Вопрос в том, нужно ли Outer изменить Inner до in. Если это так, вы должны оставить in как Inner &. В этом случае, если у вас есть const Inner &, то, конечно, вы не можете передать его Outer, потому что ссылка не позволяет вам изменять ссылочную Inner, но Outer нужно изменить Inner.

Если Outer не нужно изменять Inner, то вам нужно просто написать in как const Inner &, и в этом случае Outer можно инициализировать либо с помощью Inner &, либо * 1019. *.

Вы, конечно, можете написать:

class Inner {};

template <class T>
class Outer {
    T& in;

public:
    Outer(T& in) : in(in) {}
};

, а затем инициализировать объекты типа Outer<Inner> или Outer<const Inner>. Но Outer должен сделать что-то другое в этих двух случаях, иначе вы могли бы просто сделать in a const Inner &. И в этом случае вам, вероятно, лучше написать отдельные классы, так что ясно, что Outer делает что-то другое.

1 голос
/ 21 июня 2011

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

class Inner { /* ... */ };

class Outer {
    Inner const & in;
    bool const inIsConst;

    Inner & inMutable()
    {
        if (inIsConst)
            throw std::logic_error("in is const.");
        else
            return const_cast<Inner &>(in);
    }

public:
    Outer(Inner const & in) : in(in), inIsConst(true) {}
    Outer(Inner & in) : in(in), inIsConst(false) {}

    // always safe
    void Foo() { std::cout << in.getFoo(); }

    // will throw if *this was constructed with a const Inner
    void Bar() { inMutable().setFoo(in.getFoo() + 1); }
};

И, конечно, вы всегда можете разделить это на два класса: один, который не может изменить in, и другой, который может.

Для этого вы можете либо получить класс, который может изменить in, из класса, который не может. Или вы можете получить как из общего базового класса, который имеет общие функции в качестве защищенных членов, так и сделать соответствующие общедоступными с using Base::Function в производных классах.

1 голос
/ 21 июня 2011

Это зависит. Если две роли Outer различны для разных constness'ов (одна должна быть отредактирована, а другая нет), тогда да.

Но если две роли идентичны (это означает, что в константную или неконстантную ссылку никогда не вносятся изменения), то просто всегда принимайте const Inner& в качестве параметра. Если передается неконстантный параметр, он автоматически «повышается» до const.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...