Подтвердить что ты не робот

Существует ли какое-либо использование для класса, чтобы содержать только (по умолчанию) частные члены в С++?

Члены класса по умолчанию являются частными в С++.

Следовательно, я задаюсь вопросом, есть ли возможное использование создания класса, у которого есть все его члены (переменные и функции), установленные по умолчанию как частные.

Другими словами, существует ли какое-либо содержательное определение класса без каких-либо ключевых слов public, protected или private?

4b9b3361

Ответ 1

Существует шаблон, используемый для защиты доступа, основанный на этом классе: иногда он называется шаблоном ключа доступа (см. также чистый эквивалент эквивалентного эквивалента С++ (ответ: Идиома Адвокат-Клиент) и Как назвать этот ключевой шаблон защиты доступа?).

Доступ к protectedMethod() доступен только у друга класса ключей:

// All members set by default to private
class PassKey { friend class Foo; PassKey() {} };

class Bar
{
public:
  void protectedMethod(PassKey);
};

class Foo
{
  void do_stuff(Bar& b)
  {
    b.protectedMethod(PassKey());  // works, Foo is friend of PassKey
  }
};

class Baz
{
  void do_stuff(Bar& b)
  {
    b.protectedMethod(PassKey()); // error, PassKey() is private
  }
};

Ответ 2

Отправка тегов. Он используется в стандартной библиотеке для тегов категории итераторов, чтобы выбирать алгоритмы, которые могут быть более эффективными с определенными категориями итераторов. Например, std::distance может быть реализовано примерно так: (на самом деле это реализовано почти так же, как в gnu libstdС++, но я немного изменил его, чтобы улучшить читаемость)

template<typename Iterator>
typename iterator_traits<Iterator>::difference_type
distance(Iterator first, Iterator last)
{
      return __distance(first, last,
             typename iterator_traits<Iterator>::iterator_category());
}

Где __distance - это функция, которая перегружена, чтобы вести себя более эффективно для std::random_access_iterator_tag (которая представляет собой пустую структуру, но также может быть легко классом), просто используя last - first вместо поведения по умолчанию для подсчета сколько приращений требуется для получения first до last.

Ответ 3

Широкий доступ к ресурсам приложения?

#include <iostream>

class C {
    C() {
        std::cout << "Acquire resource" << std::endl;
    }


    ~C() {
        std::cout << "Release resource" << std::endl;
    }

    static C c;
};


C C::c;

int main() {
    return 0;
}

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


Как об использовании методов "private" вне блока объявлений: здесь я использую статический член. Таким образом, он объявляется в момент, когда частные члены доступны. Вы не ограничены конструктором/деструктором. Вы можете даже (ab) использовать статические методы, а затем вызывать методы частного экземпляра с помощью свободного интерфейса:

class C {
    C() { std::cout << "Ctor " << this << std::endl; }
    ~C() { std::cout << "Dtor" << this << std::endl; }

    static C* init(const char* mode) {
        static C theC;

        std::cout << "Init " << mode << std::endl;
        return &theC;
    }

    C* doThis() {
        std::cout << "doThis " << std::endl;

        return this;
    }

    C* doThat() {
        std::cout << "doThat " << std::endl;

        return this;
    }

    static C *c;
};


C *C::c = C::init("XYZ")
            ->doThis()
            ->doThat();

int main() {
    std::cout << "Running " << std::endl;
    return 0;
}

Этот код по-прежнему действителен (поскольку все члены C доступны в точке объявления C::c). И произведет что-то подобное:

Ctor 0x601430
Init XYZ
doThis 
doThat 
Running 
Dtor0x601430

Ответ 4

Значимые? Хорошая практика? Наверное, нет, но здесь идет:

class DataContainer {
    friend class DataUser;
    int someDataYouShouldNotWorryAbout;
};

class DataUser {
public:
    DataUser() {
        container.someDataYouShouldNotWorryAbout = 42;
    }
private:
    DataContainer container;
};

Ответ 5

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

Конечно, вы могли бы использовать friend, как было предложено, но это создало бы ненужную свертку.


С другой стороны, если вы используете struct, а не class для определения класса, то вы получаете все публичное. Это может иметь смысл.

Например:

struct MyHwMap {
  unsigned int field1 : 16;
  unsigned int field2 : 8;
  unsigned int fieldA : 24;
};

Ответ 6

По общему признанию, уродливый случай из многих, много лет назад, а не на С++, но идея все равно будет применяться:

В библиотеке времени выполнения произошла ошибка. Фактически, исправление кода, вызывающего нарушение, вызовет другие проблемы, поэтому я написал процедуру, которая обнаружила повреждающую часть кода и заменила ее на версию, которая сработала. Первоначальное воплощение не имело никакого интерфейса, кроме его создания.