Вы были бы в состоянии использовать USB-> адаптер RS232? У меня есть некоторые, и они просто используют драйвер FTDI. Затем необходимо быть в состоянии переименовать/dev/ttyUSB0 (или независимо от того, что создается) как/dev/ttyS2.
Ваш пример не терпит неудачу, k
передан по стоимости. Элемент i
является «неявно постоянным», поскольку прямые члены C
не могут быть изменены, когда экземпляр является постоянным.
Констанс говорит, что вы не можете изменять члены после инициализации, но инициализация их значениями в списке инициализации, конечно, разрешена - как еще вы могли бы дать им значение?
Что не работает, так это вызов конструктора без его выполнения публично;)
update адрес обновленный вопрос:
Да, C ++ иногда вынуждает вас к некоторой многословности, но const корректность - это обычное стандартное поведение, которое вы не можете просто переопределить, не нарушив ожиданий. Ответ Павла уже объясняет одну общую идиому, которая используется в проверенных библиотеках, таких как STL, для обхода этой ситуации.
Иногда нужно просто согласиться с тем, что у языков есть ограничения, и при этом учитывать ожидания пользователей интерфейса,
Похоже, вам нужен объект, который может заключать либо int *
(и затем вести себя как неконстантные), либо int const *
(а затем вести себя как const). Вы не можете сделать это правильно с одним классом.
Фактически, само понятие, что const
, примененное к вашему классу, должно изменить его семантику, как это неверно - если ваш класс моделирует указатель или итератор (если он оборачивает указатель, скорее всего, так и есть), то применение к нему const
должно означать только то, что он не может быть изменен сам по себе, и не должен подразумевать что-либо относительно указанного значения. Вам следует подумать о том, что STL делает для своих контейнеров - именно поэтому он имеет разные классы итератора
и const_iterator
, причем оба являются разными, но первое неявно может быть преобразовано во второе. Кроме того, в STL const итератор
не то же самое, что const_iterator
! Так что сделайте то же самое.
[РЕДАКТИРОВАТЬ] Вот хитрый способ максимального повторного использования кода между C
и const_C
, обеспечивая при этом постоянную корректность и не углубляясь в UB (с const_cast
):
template<class T, bool IsConst>
struct pointer_to_maybe_const;
template<class T>
struct pointer_to_maybe_const<T, true> { typedef const T* type; };
template<class T>
struct pointer_to_maybe_const<T, false> { typedef T* type; };
template<bool IsConst>
struct C_fields {
typename pointer_to_maybe_const<int, IsConst>::type i;
// repeat for all fields
};
template<class Derived>
class const_C_base {
public:
int method() const { // non-mutating method example
return *self().i;
}
private:
const Derived& self() const { return *static_cast<const Derived*>(this); }
};
template<class Derived>
class C_base : public const_C_base<Derived> {
public:
int method() { // mutating method example
return ++*self().i;
}
private:
Derived& self() { return *static_cast<Derived*>(this); }
};
class const_C : public const_C_base<const_C>, private C_fields<true> {
friend class const_C_base<const_C>;
};
class C : public C_base<C>, private C_fields<false> {
friend class C_base<C>;
};
Если у вас действительно мало полей, может быть проще скопировать их в обоих классах, чем использовать структуру. Если их много, но все они одного типа, то проще передать этот тип напрямую в качестве параметра типа и не беспокоиться о шаблоне оболочки const
.
Ваш вопрос не имеет смысла. Откуда вы взяли все эти предсказания «это не удастся»? Ни один из них не является даже отдаленно верным.
Во-первых, совершенно неважно, объявлен ли параметр конструктора const
или нет. Когда вы передаете по значению (как в вашем случае), вы можете передать объект const
в качестве аргумента в любом случае, независимо от того, объявлен ли параметр как const
или нет.
Во-вторых, с точки зрения конструктора, объект является константой НЕ . Независимо от того, какой объект вы строите (постоянный или нет), внутри конструктора объект никогда константа. Так что нет необходимости в mutable
или что-то в этом роде.
Почему бы вам просто не попробовать скомпилировать код (чтобы убедиться, что ничего не выйдет из строя) вместо того, чтобы делать странные необоснованные прогнозы, что что-то «выйдет из строя»?
Когда вы создаете экземпляр
const C c1(...)
, поскольку c1 является константой, его член i превращается в:
int* const i;
Как уже упоминалось, это называется неявной константой.
Теперь, позже в вашем примере, вы пытаетесь передать const int *. Итак, ваш конструктор в основном делает следующее:
const int* whatever = ...;
int* const i = whatever; // error
Причина, по которой вы получаете ошибку, в том, что вы не можете преобразовать константу в неконстантную. Указатель "любой" не может изменять то, на что он указывает (часть int - const). Указателю «i» разрешено изменять то, на что он указывает, но он не может быть изменен сам по себе (часть указателя - const).
Вы также упомянули, что хотите, чтобы ваш класс моделировал указатель. STL делает это с помощью итераторов. Модель, которую используют некоторые реализации, имеет класс под названием «const_iterator», который скрывает реальный указатель и предоставляет только константные методы для доступа к указанным данным. Также существует класс «итератор», который наследуется от «const_iterator», добавляя неконстантные перегрузки. Это прекрасно работает - это настраиваемый класс, который допускает ту же константу, что и указатели, где типы отражают указатели следующим образом:
Надеюсь, это имеет смысл :)
Также существует класс «итератор», который наследуется от «const_iterator», добавляя неконстантные перегрузки. Это прекрасно работает - это настраиваемый класс, который допускает ту же константу, что и указатели, где типы отражают указатели следующим образом:Надеюсь, это имеет смысл :)
Также существует класс «итератор», который наследуется от «const_iterator», добавляя неконстантные перегрузки. Это прекрасно работает - это настраиваемый класс, который допускает ту же константу, что и указатели, где типы отражают указатели следующим образом:Надеюсь, это имеет смысл :)
const int * не то же самое, что int * const. Когда ваш класс const, у вас есть последний (постоянный указатель на изменяемое целое число). То, что вы передаете, является первым (изменяемый указатель на постоянное целое число). По очевидным причинам они не являются взаимозаменяемыми.
Хорошо, вот что я сделал до сих пор. Чтобы разрешить наследование после константной версии класса без const_casts или дополнительных служебных данных, я создал объединение, которое в основном выглядит как ths:
template <typename T>
union MutatedPtr
{
protected:
const T * const_ptr;
T * ptr;
public:
/**
* Conversion constructor.
* @param ptr pointer.
*/
MutatedPtr(const T * ptr): const_ptr(ptr) {};
/**
* Conversion to T *.
*/
operator T *() {return ptr;}
/**
* Conversion to const T *.
*/
operator const T *() const {return const_ptr;}
};
Когда объявляется поле MutatedPtr, оно заканчивается так, что в константных методах возвращается const_ptr, а неконстантные. получить простой ptr. Он делегирует константу метода цели указателя, что имеет смысл в моем случае.
Есть комментарии?
Кстати, вы, конечно, можете сделать то же самое с не-указательными типами или даже методами, так что похоже, что введение изменяемое ключевое слово
не нужно (?)