Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22

Доступ по указателю только для чтения

20.09.2021, 22:38. Показов 3553. Ответов 39
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Мое почтение, джентльмены.
Возможно ли сделать доступ по указателю к структуре в классе - только для чтения?
Сама структура может меняться внутри класса.
Но для внешнего кода - Const.

Пример:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class XloperX
{
public:
    XloperX() {ptr = new XLOPER12();}; // создаем структуру XLOPER12 (ptr ->xltype = 0)
 
    operator LPXLOPER12() const { return ptr;}
 
    ~XloperX() { delete ptr; };
 
private:
    LPXLOPER12 ptr=NULL;
 
};
 
//...где-то в коде вне класса
XloperX out;
LPXLOPER12 delX = out;
delX->xltype = 1;//здесь нужно только чтение, менять структуру нельзя
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
20.09.2021, 22:38
Ответы с готовыми решениями:

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

Доступ только для чтения
Привет Текущий пользователь запускает приложение, на клиенте получаем SID текущего пользователя, ищем в базе данных ACCESS...

Доступ только для чтения исправление
Не могу понять, каким образом можно изменить параметр в Graphics Dpi.X Такая ошибка появляется: Ошибка CS0200 Невозможно присвоить...

39
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
23.09.2021, 20:14  [ТС]
Студворк — интернет-сервис помощи студентам
Cпасибо, понятно.
Здесь вызывается конструктор без скобок, какой из вариантов конструктора используется? Если их несколько? Как с пустыми скобками?
C++
1
2
XlopeX* ptr = new XlopeX;//вызывается конструктор
XlopeX* ptr = new XlopeX();//вызывается конструктор
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
23.09.2021, 21:05
bedvit, в данном случае эти две записи приводят к одному и тому же. Они эквивалентны.
Вызывается определенный вами конструктор без параметров.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
23.09.2021, 22:29  [ТС]
Цитата Сообщение от DrOffset Посмотреть сообщение
Потому что const, который не позволил бы менять данные - это const нижнего уровня. А когда вы применяете const к алиасу, то задаете const верхнего уровня.
Как победить и получить невозможность изменения данных через LPXLOPER12?
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
23.09.2021, 22:30
bedvit, в смысле навесить const нижнего уровня к алиасу?
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
23.09.2021, 22:47  [ТС]
DrOffset, идея в чем. Долго баловался с C API Excel в его родной сишной реализацией, разные функции вспомогательные написал. Потом ручное управление памятью стало стимулируещим фактором что-то сделать годное. Сделал оболочку-класс XlopX с голым указателем LPXLOPER12 наружу. Во все функции заходил (класс), сам управлял памятью, что-то вроде умного указателя. Сейчас решил все функции зашить в методы класса, напилить нормальный класс с Инкапсуляцией и всем остальным по феншую. Указатель LPXLOPER12 решил оставить (C API функции его кушают и иногда надо его скормить), но данные в классе менять уже не нужно. Думаю как правильно сделать.
0
 Аватар для SmallEvil
4086 / 2975 / 813
Регистрация: 29.06.2020
Сообщений: 11,000
23.09.2021, 23:15
Вроде Алексей дал нормальный совет, метод возвращающий указатель на константный объект.
Вроде проще уже никуда.
0
фрилансер
 Аватар для Алексей1153
6499 / 5730 / 1133
Регистрация: 11.10.2019
Сообщений: 15,316
24.09.2021, 06:02
SmallEvil, я вот тоже не понимаю, зачем такую непотребщину юзать LPXLOPER12, есть же исходный тип XLOPER12, всегда можно пририсовать звезду и не запутаться XLOPER12*. Это информативнее и, как выяснилось, менее грабленаступательно
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
24.09.2021, 08:21  [ТС]
Хорошо, предположим условный код был такой
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class XloperX
{
public:
    XloperX() {ptr = new XLOPER12(); ptr.xltype = 1 }; // создаем структуру XLOPER12 (ptr ->xltype = 1)
 
    operator LPXLOPER12() const { return ptr;}
 
    ~XloperX() { delete ptr; };
 
private:
    LPXLOPER12 ptr=NULL;
 
};
 
//...где-то в коде вне класса
XLOPER12 pxRes {0,0}; //XloperX pxRes; // ранее так было, теперь для чтения пример, т.к. это возвращаемая переменная
XloperX out; 
Excel12(567, &pxRes,  1, out)
Как теперь это будет выглядеть?
Excel12 функция EXCEL С API
0
фрилансер
 Аватар для Алексей1153
6499 / 5730 / 1133
Регистрация: 11.10.2019
Сообщений: 15,316
24.09.2021, 09:47
bedvit, так

Excel12(567, &pxRes, 1, &out);
там даже пример есть
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
24.09.2021, 12:52
Цитата Сообщение от bedvit Посмотреть сообщение
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class XloperX
{
public:
    XloperX() {ptr = new XLOPER12(); ptr.xltype = 1 }; // создаем структуру XLOPER12 (ptr ->xltype = 1)
 
    operator LPXLOPER12() const { return ptr;}
 
    ~XloperX() { delete ptr; };
 
private:
    LPXLOPER12 ptr=NULL;
 
};
 
//...где-то в коде вне класса
XLOPER12 pxRes {0,0}; //XloperX pxRes; // ранее так было, теперь для чтения пример, т.к. это возвращаемая переменная
XloperX out; 
Excel12(567, &pxRes,  1, out)
В целом так делать не стоит. Нет никакого смысла в этих обертках, если оно использоваться будет именно так.
Т.е. в идеале у вас не должно быть голых сишных интерфейсов вообще. Доступ к ним можно оставить, но только через специальные функции с длинными говорящими именами, с пометкой в документации, что пользоваться ими стоит только в крайнем случае.
Все штатные варианты использования сишных функций и типов нужно инкапсулировать.

Цитата Сообщение от bedvit Посмотреть сообщение
567
Такие вот магические числа - это тоже очень плохо. Что мешало использовать имя константы, которое предоставляет библиотека для него?
Естественно заставлять пользователей выписывать эти константы тоже неприемлемо. Нужно сделать набор функций (это либо свободные функции для обертки над XLOPER12, либо методы этой обертки), которые будут включать в себя все эти низкоуровневые контракты, задавать нужные константы и трасформировать сишные обобщения в конкретные типы по смыслу.

И вот если сделать это комплексно, то никакие операторы приведения будут не нужны, а константность можно контролировать естественным образом.
2
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
24.09.2021, 15:46  [ТС]
Алексей1153, out это указатель. Посмотрите внимательнее. Я хотел, что бы вы в этот пример подставили свое решение.
DrOffset, все в класс и уберу, никаких магических чисел не будет, я писал пример по памяти, и поставил условное число, для каждой функции есть определенное имя. Голые интерфейсы хотел убрать в чтение (в const?). За этим и тема, как убрать красиво.
0
фрилансер
 Аватар для Алексей1153
6499 / 5730 / 1133
Регистрация: 11.10.2019
Сообщений: 15,316
24.09.2021, 15:58
Цитата Сообщение от bedvit Посмотреть сообщение
out это указатель. Посмотрите внимательнее.
вот, смотрю внимательнее:
Цитата Сообщение от bedvit Посмотреть сообщение
class XloperX
{
....
};

XloperX out;
это экземпляр структуры XloperX. Не указатель

Добавлено через 2 минуты
аа, всё, понял, про что )

Добавлено через 4 минуты
собственно, если бы поле было паблик, то
C++
1
Excel12(567, &pxRes, 1, out.ptr);
если сделать метод XLOPER12* GetConstPointer()const{return ptr;}, то
C++
1
Excel12(567, &pxRes, 1, out.GetConstPointer());
с лямбдой
C++
1
2
3
4
    out.InvokeToReadOnly([&pxRes](const XloperX_private_data& private_data)
    {
        Excel12(567, &pxRes, 1, private_data.ptr); 
    });
1
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
24.09.2021, 23:05
Цитата Сообщение от bedvit Посмотреть сообщение
как убрать
Вообще обертка над этой библиотекой не такая уж и проста задача, если поставить цель сделать именно "красиво".
Не претендуя на полноту и абсолютную истину предложу вариант для старта:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
namespace detail {
 
class Xloper12
{
    template <typename ...Ts>
    friend Xloper12 invoke(int f, Ts const& ...args);
 
public:
    Xloper12() : m_value()
    { }
    Xloper12(Xloper12 && other) {
        // move implementation
    }
    ~Xloper12() {
        ::Excel12(xlFree, 0, 1, &m_value);
    }
 
    Xloper12(Xloper12 const&) = delete;
    Xloper12& operator=(Xloper12 const&) = delete;
 
    explicit Xloper12(bool val)
    {
        m_value.xltype = xltypeBool;
        m_value.val.xbool = val;
    }
    bool toBool() const {
        return m_value.val.xbool;
    }
 
    explicit Xloper12(double val)
    {
        m_value.xltype = xltypeNum;
        m_value.val.num = val;
    }
    double toNumber() const {
        return m_value.val.num;
    }
 
    explicit Xloper12(int val)
    {
        m_value.xltype = xltypeInt;
        m_value.val.w = val;
    }
    int toInteger() const {
        return m_value.val.w;
    }
 
    wchar_t const* toWString() const {
        return m_value.val.str + 1;
    }
    int lenWString() const {
        return (int)m_value.val.str[0];
    }
 
    int type() const {
        return m_value.xltype;
    }
 
private:
    LPXLOPER12 internal() {
        return &m_value;
    }
    XLOPER12 const* internal() const {
        return &m_value;
    }
 
private:
    XLOPER12 m_value;
};
 
template < typename ...Ts >
Xloper12 invoke(int f, Ts const& ...args)  {
    Xloper12 ret;
    ::Excel12(f, ret.internal(), sizeof...(args), Xloper12(args).internal()...);
    /*error check*/
    return ret;
}
 
} // detail
C++
1
2
3
4
int main()
{
    detail::Xloper12 result = detail::invoke(567, 3.);
}

Это, может быть, так сказать, первый уровень абстракции.
На втором уровне предстоит определить конкретные функции, с конкретными типами уже без привязки к xloper вовсе.
1
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
27.09.2021, 08:49  [ТС]
DrOffset, спасибо за реализацию и достаточно глубокое погружение в тему. Если ваш код в дальнейшем будет использоваться вами, или есть интерес к даннной теме, то здесь я могу отметить несколько моментов и нюансов.
При обсуждении здесь я понял концепцию, как я хочу видеть данный класс. Благодарю участвовавших.
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
30.09.2021, 22:54  [ТС]
Что будет во втором случае?
Цитата Сообщение от DrOffset Посмотреть сообщение
//класс
operator LPXLOPER12() const { return ptr;}

//где то в коде
LPXLOPER12 l = x.LP(); //Ошибка C2440 инициализация: невозможно преобразовать "const XLOPER12 *" в "LPXLOPER12"

LPXLOPER12 l = (LPXLOPER12)x.LP();//компилируется
l->xltype = 0;//присваивается. Что получим в итоге?
0
фрилансер
 Аватар для Алексей1153
6499 / 5730 / 1133
Регистрация: 11.10.2019
Сообщений: 15,316
30.09.2021, 23:05
--del--

Добавлено через 1 минуту
сорри, понял )

Добавлено через 2 минуты
Цитата Сообщение от bedvit Посмотреть сообщение
LPXLOPER12 l = (LPXLOPER12)x.LP();//компилируется
указатель на константу приводится к указателю на не константу. Не очень хорошее занятие
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
30.09.2021, 23:26
Цитата Сообщение от bedvit Посмотреть сообщение
Что будет во втором случае?
Я утверждаю, что оператор "преобразования к потрохам" класса - это:
1) Плохой дизайн;
2) Как следствие - нарушение инкапсуляции;
3) Все дальнейшие проблемы - это следствие первых двух.

Добавлено через 4 минуты
Цитата Сообщение от bedvit Посмотреть сообщение
LPXLOPER12 l = (LPXLOPER12)x.LP();//компилируется
l->xltype = 0;//присваивается. Что получим в итоге?
Если ptr внутри x указывает на константу, то получим UB.
Если нет, то формально ничего страшного не произойдет. Мы навесили конст внутри класса, а потом сняли его явно кастом снаружи. Можно присваивать, но это все еще кривой код, оправдание которому нужно было бы долго и нудно предъявлять на ревью (если бы оно имело место).
0
 Аватар для bedvit
1210 / 261 / 22
Регистрация: 20.05.2016
Сообщений: 1,147
Записей в блоге: 22
01.10.2021, 08:38  [ТС]
1. Так делать плохо, но кто мешает плохому кодеру так сделать? Вернее даже не плохо, а нужно думать зачем ты так сделал. А как с инкапсуляцией у std::string::c_str(), это тоже константный указатель на сишную строку. Аналогичная ситуация?

2. Из замеченного копмилятор VS 2017 присваивает значение xltype в l, но значения в х остаётся прежним. Будет все таки присвоено значение в х или нет?) И плохому кодеру этот лайфхак не поможет?
0
фрилансер
 Аватар для Алексей1153
6499 / 5730 / 1133
Регистрация: 11.10.2019
Сообщений: 15,316
01.10.2021, 09:45
bedvit,
1) - никто не мешает сделать, если только потом не хочется бегать и выяснять, где и что загадочно не работает.
У std::string "память" редактируемая, не константная. Метод c_str() возвращает указатель на константу, но рядом же есть метод data(), позволяющий править значения в строке напрямую. То есть, такое вмешательство официально разрешено разработчиками класса
0
19505 / 10108 / 2463
Регистрация: 30.01.2014
Сообщений: 17,828
01.10.2021, 10:32
Цитата Сообщение от bedvit Посмотреть сообщение
А как с инкапсуляцией у std::string::c_str(), это тоже константный указатель на сишную строку. Аналогичная ситуация?
Нет, не аналогичная. Т.к. явный вызов c_str - задает контракт, который виден в коде, а неявный вызов оператора "преобразования к потрохам", явных контрактов не задает.

Цитата Сообщение от bedvit Посмотреть сообщение
кто мешает плохому кодеру так сделать?
Этому должен помешать ревьюер.

Цитата Сообщение от bedvit Посмотреть сообщение
Из замеченного копмилятор VS 2017 присваивает значение xltype в l, но значения в х остаётся прежним.
Полный код, пожалуйста.

Цитата Сообщение от bedvit Посмотреть сообщение
Будет все таки присвоено значение в х или нет?)
Если вы сейчас покажете полный код и там будет UB, то в таком виде ответа на этот вопрос не существует. Ответ - это UB и все.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
01.10.2021, 10:32

Ошибка - доступ только для чтения. ( Color )
Доброго! При попытке записать коэффициент для цветового канала: tempCol.R = Convert.ToByte(Convert.ToDouble(color.R) * a); в...

Доступ НЕ только для чтения к документу из журнала
Господа знающие! Столкнулся с такой проблемой: Задача: Есть журнал документов. Добавляю к нему кнопочку. Хочу чтобы по этой кнопочке...

“TreeNode.IsExpanded” — доступ только для чтения
Загружаю в treeView дерево из файла &quot;json&quot;. Метод public static class TreeRepository { public class DataNode { ...

Невозможно присвоить значение свойству или индексатору -- доступ только для чтения!
Здравствуйте! Выходит ошибка: Невозможно присвоить значение свойству или индексатору &quot;System.Windows.Controls.ItemsControl.Items&quot;...

Невозможно присвоить значение свойству или индексатору - доступ только для чтения
Доброго времени суток, ребят пишет ошибку: Невозможно присвоить значение свойству или индексатору &quot;string.this&quot; -- доступ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Опции темы

Новые блоги и статьи
Калькулятор для расчета родства
russiannick 07.08.2026
1. Задача: Создать калькулятор для расчета родства. Родственных связей существует 8 ступеней, такие как: p - отец P - мать q - муж Q - жена b - брат B - сестра s - сын S - дочь
Мир по моей воле
kumehtar 07.08.2026
Когда-то кажется, что всё просто. Ты весь такой светлый. Причиняешь добро. Борешься за справедливость в этом тёмном мире. Потом начинаешь замечать одну неприятную вещь. Почти каждый хороший. . .
Кредитный калькулятор
Maks 05.08.2026
Решение задачи по прикладной информатике средствами 1С. Задача: Напишите приложение-калькулятор, которое помогает рассчитывать параметры кредита для аннуитетного и дифференцированного видов. . .
У нас сейчас поговорку "Опять 25" нужно переделать на "Опять +35".
kumehtar 04.08.2026
С ностальгией вспоминаю времена моего детства, когда у нас и правда +25 - была максимальная температура летом. Раньше +25 °C реально казались вершиной жары, когда можно было весь день пропадать на. . .
Как ИИ начал спорить и врать (возможно почуяв опасность для себя от индустрии - уход от электроники).
Hrethgir 04.08.2026
Недельный диалог, на фоне событий с НПЗ. Да, из спирта можно получать бензин, и это не сложно. Но потом в схеме я решил избавиться от насоса, при этом полностью сделав контроль подачи спирта в. . .
Термопринтер QR701
Argus19 03.08.2026
Термопринтер QR701 Купил два термопринтера QR701. На сэлф-тесте написано: Language: PC936 (GB18030). Что означает, что принтеры могут печатать только латиницу и китайские иероглифы. Так же. . .
Создание формы заимствованного документа
Maks 03.08.2026
Задача: Необходимо создать собственную форму заимствованного документа. На форме должен быть реквизит "Покупатель", а также табличная часть со следующими реквизитами: - Расчетный счет покупателя. . .
Задача предоставления скидок покупателям
Maks 03.08.2026
Задача: В документе "Продажи" необходимо реализовать функционал предоставления скидок покупателям. Скидка должна автоматически рассчитываться и подставляться в соответствующее поле при выборе. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru