Помогите разобраться с классами

Тема в разделе "LANGS.C", создана пользователем Magnum, 17 авг 2008.

  1. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    САБЖ
    сейчас занялся изучением классов.

    Вопрос такой
    МОжно ли как-то сделать класс, в котором будут паблик члены(переменные), но которые можно изменять только методами класса, а извне только читать ?
     
  2. Ursus

    Ursus Member

    Публикаций:
    0
    Регистрация:
    15 мар 2006
    Сообщения:
    238
    Адрес:
    Russia
    Нед.
     
  3. toto

    toto New Member

    Публикаций:
    0
    Регистрация:
    15 июн 2008
    Сообщения:
    36
    Сорри если ступил, но что мешает сделать Set метод закрытым ( т.е. писать ), а Get открытым ( т.е. читать ).
     
  4. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    А зачем? Для этого принято писать getter/setter.
     
  5. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    не знал
    спасибо
    я только разбираюсь с классами

    Еще вопрос

    В проекте по умолчанию соглашение о передаче аргументов _cdecl

    а можно ли как-то сделать так, чтобы в моем классе (в методах моего класса) по умолчанию соглашение было _fastcall ? т.е. чтобы не прописывать перед каждым методом _fastcall
     
  6. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    А зачем такой подход собственно? Если для оптимизации, то компилятор обычно оптимизирует функции такого типа посредством inline:
    Код (Text):
    1. HWND TWindow::get_Handle ()
    2. {
    3.     return m_hWnd;
    4. }
    Кроме того, можно подстраховаться и таким образом:
    Код (Text):
    1. HWND TWindow::get_Handle ()
    2. {
    3.     ASSERT (::IsWindow (m_hWnd));
    4.     return m_hWnd;
    5. }
    В RELEASE-е всё это будет убрано и код получится как будто ты использовал член класса напрямую:
    Код (Text):
    1. TWindow win;
    2. HWND h = win.get_Handle ();
    3.  
    4. // In RELEASE (with full optimization) Build turns into:
    5.  
    6. TWindow win;
    7. HWND h = win.m_hWnd;
     
  7. bigredcat

    bigredcat New Member

    Публикаций:
    0
    Регистрация:
    3 сен 2007
    Сообщения:
    54
    Если после создания объекта не требуется изменять данное-член, то можно сделать и так.
    Код (Text):
    1. class A{
    2. public:
    3.     A(int init_val = 0) : val(init_val) {}
    4.     const int val;
    5. };
    Хотя и в этом случае по хорошему не стоит его объявлять открытым, а стоит использовать int GetVal() {return val;}
    Код (Text):
    1. class A{
    2.     const int val;
    3. public:
    4.     A(int init_val = 0) : val(init_val) {}
    5.     int GetVal() {return val;}
    6. };
     
  8. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    AsmGuru62
    спасибо

    и еще вопрос

    Обычно когда все члены структуры мне нужно было сбросить в ноль, я юзал memset

    примерно так
    memset((void*)&mystruct, 0, sizeof(mystruct));

    а как занулить все переменные класса?
    Если в классе около 100 переменных и еще методы.
    Не занулять же каждую по отдельности?
    Я так понимаю зануление нужно в конструкторе писать.
    Но мемсет не работает.
    Компилятор пишет illegal use of expression
     
  9. bigredcat

    bigredcat New Member

    Публикаций:
    0
    Регистрация:
    3 сен 2007
    Сообщения:
    54
    Да, вроде компилится без ошибок
    Код (Text):
    1. #include <iostream>
    2. class A{
    3.     int val1;
    4.     int val2;
    5. public:
    6.     int GetVal1() {return val1;}
    7.     int GetVal2() {return val2;}
    8. };
    9.  
    10. int main()
    11. {
    12.     using std::cout;
    13.     using std::endl;
    14.  
    15.     A a;
    16.     memset((void*) &a, -1, sizeof(a));
    17.  
    18.     cout << a.GetVal1() << endl;
    19.     cout << a.GetVal2() << endl;
    20.    
    21.     return 0;
    22. }
     
  10. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    Можно попробовать переопределить operator new для класса:
    Код (Text):
    1. class A
    2. {
    3.     // ...
    4.     void* operator new (size_t nBytes);
    5.     // ...
    6. };
    7.  
    8.  
    9. ...
    10.  
    11. void* A::operator new (size_t nBytes)
    12. {
    13.     return calloc (1, nBytes);
    14. }
    Но тогда зануление происходит только при динамическом создании объекта, а при создании как локальной переменной зануления не будет:
    Код (Text):
    1. A* pA = new A; // All members are cleared
    2. A a2; // Members are NOT cleared!
    Скорее всего придётся обнулять всё в конструкторе.
     
  11. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    bigredcat
    Попробуй сделать виртуальный метод в твоём примере и вызвать его после очистки класса. Теоретически, адрес на таблицу виртуальных методов должен запортиться.
     
  12. bigredcat

    bigredcat New Member

    Публикаций:
    0
    Регистрация:
    3 сен 2007
    Сообщения:
    54
    Странно, но работают и виртуальные функции.
    Код (Text):
    1. #include <stdio.h>
    2. #include <iostream>
    3. class A{
    4.     int val1;
    5.     int val2;
    6.     char* val3;
    7. public:
    8.     virtual void SetVal3(char* new_val3) {val3 = new char[strlen(new_val3) + 1]; strcpy(val3, new_val3);}
    9.     int GetVal1() {return val1;}
    10.     virtual int GetVal2() {return val2;}
    11.     virtual char* GetVal3() {return val3;}
    12. };
    13.  
    14. int main()
    15. {
    16.     using std::cout;
    17.     using std::endl;
    18.  
    19.     A a;
    20.     memset((void*) &a, -1, sizeof(a));
    21.  
    22.     a.SetVal3("Test");
    23.     cout << a.GetVal1() << endl;
    24.     cout << a.GetVal2() << endl;
    25.     cout << a.GetVal3() << endl;
    26.    
    27.     return 0;
    28. }
     
  13. bigredcat

    bigredcat New Member

    Публикаций:
    0
    Регистрация:
    3 сен 2007
    Сообщения:
    54
    Посмотрел в debug, оказалось memset не трогает таблицу _vfptr

    Однако посмотрел еще раз. Оказывается еще как трогает таблицу вирт. функций (портит адреса виртуальных функций). Только не понятно, почему в примере выше виртуальные функции все-таки записывают и возвращают строку.
     
  14. Magnum

    Magnum New Member

    Публикаций:
    0
    Регистрация:
    29 дек 2007
    Сообщения:
    925
    сколько читаю - не пойму
    чем отличаются обычные методы от виртуальных?
     
  15. zhindos

    zhindos New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    142
    Для обычных методов (при вызове) компилятор сам подставляет адрес на этапе компиляции. Для виртуальных генерится код обращения к _vfptr, который занимает первые 4 байта объекта и по смещению от начала таблицы находится адрес нужной ф-ии. Фишка в том, что тип объекта у тебя может быть базовый, а _vfptr при этом может быть на таблицу виртуальных ф-ий производного класса. Так реализуется полиморфизм в cpp
     
  16. _DEN_

    _DEN_ DEN

    Публикаций:
    0
    Регистрация:
    8 окт 2003
    Сообщения:
    5.383
    Адрес:
    Йобастан
    Magnum

    Обнуление переменных:

    class A { ... };

    A a = A(); // Вот и обнулили.

    А если в твоем классе "около 100 переменных", то это уже плохо - разбей класс на несколько классов по смыслу.
     
  17. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Magnum
    Любые операции над внутренними данными класса надо писать внутри класса. Все эти memset за пределами класса предложенные здесь -- просто само по себе неверное решение, так нельзя писать.

    Но лично меня смутило другое, что это за класс такой с сотней переменных. Это уже твоя ошибка проектирования, скорее всего. Либо класс выполняет несколько задач и его необходимо декомпозировать, как уже предложил _DEN_, либо ты забыл, что в методах могут быть локальные переменные и вынес всё в общие секции.
     
  18. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    bigredcat
    Потому что в там нет виртуальности и полиморфизма. Компилятор заменил вызовы через vtable на прямые.

    Попробуй вот такой пример:

    Код (Text):
    1. class A
    2. {
    3. protected:
    4.     std::string s;
    5.  
    6. public:
    7.     A():
    8.       s("")
    9.     {};
    10.  
    11.     virtual ~A() {};
    12.  
    13.     virtual void set_string(std::string& new_s)
    14.     {
    15.         s = new_s;
    16.     }
    17.  
    18.     virtual std::string get_str() = 0;
    19. };
    20.  
    21. class B: public A
    22. {
    23. public:
    24.     B() {};
    25.     virtual ~B() {};
    26.  
    27.     virtual std::string get_str()
    28.     {
    29.         return s;
    30.     }
    31. };
    32.  
    33.  
    34. int main()
    35. {
    36.     A* b = new B;
    37.  
    38.     b->set_string(std::string("Hello"));
    39.  
    40.     std::cout << b->get_str() << std::endl;
    41.     memset((void*)b, -1, sizeof(B));
    42.     std::cout << b->get_str() << std::endl;
    43.  
    44.     return 0;
    45. }
     
  19. W4FhLF

    W4FhLF New Member

    Публикаций:
    0
    Регистрация:
    3 дек 2006
    Сообщения:
    1.050
    Полиморфизм, minimum edition :)

    Код (Text):
    1. class Base
    2. {
    3. public:
    4.     virtual void name()
    5.     {
    6.         std::cout << typeid(*this).name() << std::endl;
    7.     }
    8. };
    9.  
    10. class Car: public Base { /* ... */ };
    11. class Bicycle: public Base { /* ... */ };
    12. class Plane: public Base { /* ... */ };
    13.  
    14. void f(Base* b)
    15. {
    16.     b->name();
    17. }
    18.  
    19. void main()
    20. {
    21.     f(new Car);
    22.     f(new Plane);
    23.     f(new Bicycle);
    24. }
     
  20. varnie

    varnie New Member

    Публикаций:
    0
    Регистрация:
    2 янв 2005
    Сообщения:
    1.785
    W4FhLF
    придирусь:)
    1. http://www.research.att.com/~bs/bs_faq2.html#void-main
    2. a delete для объектов кто делать будет?
    3. почему нету виртуального деструктора в классе Base не ясно

    если я что-то выше по беседе упустил - звиняйте.