Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Наследование: создается один большой класс? методы и this 
:(
    Опции темы
Gunslinger
Дата 11.1.2010, 17:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Видимо для оптимизации, методы для всех объектов одного класса создаются в единственном экземпляре. А как при множественном наследовании? Методы всех наследуемых классов компилятор организовывает в один последовательный блок памяти или нет?
Например, псевдокод:
Код

class A
{
   int d;
   int k;
   void ff(){};
}

class B
{
  double sa;
  int ms(){};
}

class C: public A, public B
{
  int g;
 int m;
 void g(){};

C obj;
};


В памяти будет вроде:
Код

struct obj
{
   int d;
   int k;
  double sa;
} 

struct С
{
   void ff(){};
   int ms(){};
   void g(){};
}
?
И вариант, когда в коде создаем не только объект-наследник, но и объекты классов А и В. 


Это сообщение отредактировал(а) Gunslinger - 11.1.2010, 17:29
PM MAIL   Вверх
xvr
Дата 11.1.2010, 17:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



С точки зрения расположения в памяти методы класса ничем не отличаются от обычных функций. И в памяти они будут лежать как обычные функции. С переменными класса эта память никак не пересекается.

PM MAIL   Вверх
mes
Дата 11.1.2010, 18:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  11.1.2010,  16:26 Найти цитируемый пост)
Видимо для оптимизации, методы для всех объектов одного класса создаются в единственном экземпляре.

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

Код

class A
{
  public:

   static void sf ();
   void f();  
   int i;
};
A a;

фактически :
Код

namespace A // classspace A
{
   struct  this_t
   {
      int i;
   };
   void sf ();
   void f (this_t * this)
}

A::this_t a;



Это сообщение отредактировал(а) mes - 11.1.2010, 18:56


--------------------
PM MAIL WWW   Вверх
EnergoHokum
Дата 12.1.2010, 11:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 600
Регистрация: 10.11.2006
Где: Россия, Ставропол ь

Репутация: нет
Всего: 6



Здесь неплохо расписано, как выглядит наследование C++ на низком уровне.
PM MAIL ICQ   Вверх
Gunslinger
Дата 13.1.2010, 10:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



EnergoHokum, ок.
Из статьи:
"При наследовании в результирующем классе объединяются только члены с данными! Все методы существуют в единственном экземпляре."
Я так понял, что компилятор для кода
Код

class A{
  public:
    int a1(){};
}

class B{
  public:
    int b1(){};
}      

class C: public A, public B{
  public:
    int c1(){};
}

создаст не
Код

namespace C{
   int a1(){};
   int b1(){};
   int c1(){};
}

а... "распылит", что ли, по памяти.
Код

namespace А{
  int a1(){};
}
//какая-то информация
namespace B{
  int b1(){};
}
//какая-то информация
namespace C{
  int c1(){};
}

Есть ли вообще прикладной смысл в этом знании? Какая-то мысль с приведениями указателей крутится.
PM MAIL   Вверх
zim22
Дата 13.1.2010, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(Gunslinger @  11.1.2010,  16:26 Найти цитируемый пост)
А как при множественном наследовании?

почитай Lippman. Inside the C++ Object Model
я думаю там будет ответ на твой вопрос smile


--------------------
PM MAIL   Вверх
mes
Дата 13.1.2010, 12:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  13.1.2010,  09:15 Найти цитируемый пост)
а... "распылит", что ли, по памяти.

по какой памяти ? 
Код

void f1 () {}
void f2 () {}

и
Код

namespace a {
void f1 () {}
}
namespace b {
void f2 () {}
}

размещаются в памяти одинаково, только не в той памяти которую Вы судя по всему, имели ввиду.





Это сообщение отредактировал(а) mes - 13.1.2010, 12:29


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 14.1.2010, 13:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(zim22 @  13.1.2010,  11:13 Найти цитируемый пост)
почитай Lippman. Inside the C++ Object Model
я думаю там будет ответ на твой вопрос smile 

Нашел Липпмана, которого ты в прошлой теме советовал, но по отзывам в переводе неточности, а в коде встречаются ошибки. Так что я не рискнул. Эту книгу только на торрентсе нашел, пока не скачал.

Цитата(mes @  13.1.2010,  12:08 Найти цитируемый пост)
по какой памяти ? 

Тогда в адресном пространстве?smile Друг за другом, вроде: по адресу 1 - метод класса А, по адресу 2 - метод класса В, по адресу 3 - метод класса С (в каждом по одному методу). Если так, тогда понятно, почему можно сделать так:
Код

class A{public: a1(){};
};
class B{public: b1(){};
};
class C: public A, public B {public: c1(){}
};

С *pC=new C;
pC->c1();
A *pA=(A)pC;
pA->a1();

ps. Возможны синтаксические неточности.

Это сообщение отредактировал(а) Gunslinger - 14.1.2010, 13:13
PM MAIL   Вверх
mes
Дата 14.1.2010, 13:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  14.1.2010,  12:11 Найти цитируемый пост)
Тогда в адресном пространстве?

Цитата(Gunslinger @  14.1.2010,  12:11 Найти цитируемый пост)
Если так, тогда понятно,

Ваш пример не понял.. можете объяснить, как создание объекта связано с расположением функций(-членов)?




--------------------
PM MAIL WWW   Вверх
zim22
Дата 14.1.2010, 13:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


depict1
****


Профиль
Группа: Завсегдатай
Сообщений: 2682
Регистрация: 15.1.2009
Где: Украина

Репутация: 24
Всего: 69



Цитата(Gunslinger @  14.1.2010,  12:11 Найти цитируемый пост)
Нашел Липпмана, которого ты в прошлой теме советовал,

то другая книга

Цитата(Gunslinger @  14.1.2010,  12:11 Найти цитируемый пост)
 но по отзывам в переводе неточности, а в коде встречаются ошибки

перевод очень хорош. в коде есть пара ошибок, но они легко обнаруживаются



--------------------
PM MAIL   Вверх
Gunslinger
Дата 14.1.2010, 13:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(zim22 @  14.1.2010,  13:18 Найти цитируемый пост)
перевод очень хорош. в коде есть пара ошибок, но они легко обнаруживаются

Тогда сегодня скачаю, заодно и по объектной модели.

Цитата(mes @  14.1.2010,  13:14 Найти цитируемый пост)
Ваш пример не понял.. можете объяснить, как создание объекта связано с расположением функций(-членов)?

Попробую... Вот мои мысли:
1. Приведение указателя -- адрес остается тем же, только меняется тип. Т.е. указывал на участок памяти одного размера (начиная с какого-то адреса), теперь указывает на участок памяти другого размера (при этом, начиная с того же самого адреса). 
2. Наследование С: public A, pubic B, ... . Методы классов родителей и наследника объединяются и располагаются в памяти друг за другом, в порядке списка наследования -- сначала А, затем В и С. Таким образом с помощью указателя можно получать доступ к методам не только наследника, но и всех его родителей, перемещаясь по этой области памяти. То есть тот же самый код:
Код

С *pC=new C; // -- Выделили область памяти для всех методов: и наследника, и родителей  
pC->c1();// -- Обратились к методу наследника. Как обычно
A *pA=(A)pC;// -- Теперь указатель чуть меньшего размера, чем область С, при этом начальный адрес тот же, что и у pC
pA->a1(); //-- Таким образом получили доступ к методу одного из родителе, к А.



PM MAIL   Вверх
xvr
Дата 14.1.2010, 14:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата

Попробую... Вот мои мысли:
Странные у вас мысли  smile Кажется у вас путанница в некоторых базовых понятиях - методы объектов НЕ ЛЕЖАТ вместе с их данными. Они вообще никак не привязанны к конкретным экземплярам этих объектов. При наследовании объектов методы родителя остаются как были, никто никаких новых экземпляров этих методов не создает.
Методы - это ОБЫЧНЫЕ функции с неявным дополнительным формальным параметром.

PM MAIL   Вверх
Gunslinger
Дата 14.1.2010, 15:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(xvr @  14.1.2010,  14:17 Найти цитируемый пост)
методы объектов НЕ ЛЕЖАТ вместе с их данными. 

Я не писал о данных. При чем здесь они? Я уже знаю, что они лежат отдельно, а у методов есть this на них. 

Цитата(xvr @  14.1.2010,  14:17 Найти цитируемый пост)
При наследовании объектов методы родителя остаются как были, никто никаких новых экземпляров этих методов не создает.

Вот это я и хочу понять. Получается, например, так: есть 2 класса и есть класс 3 - их наследник. Копию родителей не создает, понятно. А как располагает в адресном пространстве? Друг за другом или нет?
PM MAIL   Вверх
mes
Дата 14.1.2010, 15:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  14.1.2010,  12:52 Найти цитируемый пост)
Попробую... Вот мои мысли:

зря Вы перешли к множественному наследованию не разобравшись с классическим.


Цитата(Gunslinger @  14.1.2010,  12:52 Найти цитируемый пост)
Приведение указателя -- адрес остается тем же, только меняется тип. Т.е. указывал на участок памяти одного размера (начиная с какого-то адреса), теперь указывает на участок памяти другого размера (при этом, начиная с того же самого адреса). 


При множественном наследовании это не так. Адрес меняется.
Код


struct A { int i; };
struct B { int i; };
struct AB : A, B {};

int main() {

AB ab;
std::cout  << (A*)&ab << " "<<  (B*)&ab << std::endl;
}


Цитата(Gunslinger @  14.1.2010,  12:52 Найти цитируемый пост)
Методы классов родителей и наследника объединяются и располагаются в памяти друг за другом

Какое отношение расположение методов имеет к указателю this ? какой бы ни был this методы всегда продолжают лежать на своем месте, и
Цитата(xvr @  14.1.2010,  13:17 Найти цитируемый пост)
методы объектов НЕ ЛЕЖАТ вместе с их данными


Цитата(Gunslinger @  14.1.2010,  12:52 Найти цитируемый пост)
Таким образом с помощью указателя можно получать доступ к методам не только наследника

Кажись я понял в чем дело.. Вас сбила терминология. 

Есть два разных добирания... Когда речь идет о добирании до методов, роль играет не значение указателя (оно может бытэ любым хоть NULL), а его тип.
И второе добирание, когда функция-член посредством this хочет добраться до данных. 
В примере ниже мы не используем ни виртуальных ни данных объекта, поэтому смело можем передавать NULL в качестве аргумента.
(но не забываем что пример тестовый и в реале подобный подход не рекомендуется)
И в зависимости от приведения у нас выберется нужная функция.

Код

struct A {  void f (){ std::cout << 1; } };
struct B {  void f (){ std::cout << 2; } };
struct AB : A, B {};

int main() {

AB * ab = NULL;
//   ab->f(); // request for member `f' is ambiguous
            // так как обе  f одинаково подходят.   
   
 ((A*) ab) ->f();
 ((B*) ab) ->f(); 
}







--------------------
PM MAIL WWW   Вверх
mes
Дата 14.1.2010, 16:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  14.1.2010,  14:33 Найти цитируемый пост)
А как располагает в адресном пространстве? Друг за другом или нет? 

данные друг за другом с учетом выравнивания, а функции(-члены) где вздумается.
Более того на самом деле генерируется на много больше функций, чем Вы видете в коде.




--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 14.1.2010, 16:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  14.1.2010,  15:57 Найти цитируемый пост)

struct A {  void f (){ std::cout << 1; } };
struct B {  void f (){ std::cout << 2; } };
struct AB : A, B {};
int main() {
AB * ab = NULL;
//   ab->f(); // request for member `f' is ambiguous
            // так как обе  f одинаково подходят.   
   
 ((A*) ab) ->f();
 ((B*) ab) ->f(); 
}

Да, именно об этом я и спрашивал: что через один указатель мы можем получать доступ как к методам наследника, так и к методам родителя(лей). Отчасти поэтому и выбрал пример с множественным наследованием -- яснее видно. Теперь, когда мы говорим об одном и том же -- повторю. Физически A::f(), B::f() и C::f()(если есть) компилятор располагает в памяти друг за другом? Т.к. благодаря этому приведение указателя на наследник к указателю на родителя имеет смысл.

Цитата(mes @  14.1.2010,  15:57 Найти цитируемый пост)
Цитата(Gunslinger @  14.1.2010,  12:52 Найти цитируемый пост)
Приведение указателя -- адрес остается тем же, только меняется тип. Т.е. указывал на участок памяти одного размера (начиная с какого-то адреса), теперь указывает на участок памяти другого размера (при этом, начиная с того же самого адреса). 

При множественном наследовании это не так. Адрес меняется.

Т.е. при одиночном наследовании -- все так, как я написал? А при множественном?

PM MAIL   Вверх
mes
Дата 14.1.2010, 16:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  14.1.2010,  15:38 Найти цитируемый пост)
Физически A::f(), B::f() и C::f()(если есть) компилятор располагает в памяти друг за другом? Т.к. благодаря этому приведение указателя на наследник к указателю на родителя имеет смысл.

нет.. 
1. не обязательно друг за другом.. 
2. функции вообще может не существовать в машинном коде 
3. НЕ благодаря этому приведение имеет смысл

Добавлено через 13 минут и 37 секунд
Цитата(Gunslinger @  14.1.2010,  15:38 Найти цитируемый пост)
Т.е. при одиночном наследовании -- все так, как я написал?

нет. Сути Вы не написали.. то что адрес при преобразовании не меняется, нам роли не играет..

Вот еще один пример :

Код

struct A
{  
   void f () { std::cout <<"A::f() "; }
   int i;
};
struct B : A {
   void f() { std::cout <<"B::f() "; }
};


int main (int argc, char* argv[])
{
    B b;
    A a;
    
    a.f (); // тут по типу подбирается какaя функция
    b.f();  // больше подходит.
    
    b.A::f(); // тут явно укаызваем какую функцию 
    b.B::f(); // хотим вызвать
}    

т.е  когда мы явно не указываем каую функцию мы хотим вызвать, еще на стадии компиляции заменяется 
  a.f (); на a.A::f(); 
  b.f();  на b.B::f(); 
потому как компилятор обладает всей необходимой инфой для этого  на тот момент времени.



--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 14.1.2010, 17:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  14.1.2010,  16:47 Найти цитируемый пост)
1. не обязательно друг за другом.. 

Значит в памяти могут располагаться так (х - какая-либо другая инфа; С -наследник А и В):
xx[A::f()]xxxxxxxx[B::f()]xxxxx[C::f()]xxx
а не так:
ххххххxx[A::f()][B::f()][C::f()]xxxххххххх

Цитата(mes @  14.1.2010,  16:47 Найти цитируемый пост)
3. НЕ благодаря этому приведение имеет смысл

Тогда при приведении:
1.  компилятор должен определить, где начинается, например, А и положить в указатель адрес на область А.
2. можно привести указатель с С на указатель не только к ео родителям А, В, а к любому другому. Например, к какому-нибудь Е, который от А и В вообще  не наследует.


Это сообщение отредактировал(а) Gunslinger - 14.1.2010, 17:16
PM MAIL   Вверх
baldina
Дата 14.1.2010, 17:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



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

вот пример:

Код

// C++
class A {
 int x;
public:
 void f1 ();
 void f2 ();
 void f3 ();
};

void foo ()
{
  A a;
  a.f1(); // фактически вызов A::f1(&a);
  a.f2();
  a.f3();
}

void A::f2 () { x = 2; }
void A::f3 () { x = 3; }
void A::f1 () { x = 1; }

// то же самое на C

typedef struct {
  int x;
} A;

void f2 (A*a) { a->x = 2; }
void f3 (A*a) { a->x = 3; }
void f1 (A*a) { a->x = 1; }

void foo ()
{
  A a;
  f1(&a);
  f2(&a);
  f3(&a);
}


Добавлено через 7 минут и 17 секунд
Цитата

2. можно привести указатель с С на указатель не только к ео родителям А, В, а к любому другому. Например, к какому-нибудь Е, который от А и В вообще  не наследует.

Технически можно. Практически не нужно. ЯВУ существует как раз для того, что бы не думать об адресах и т.п., а думать в терминах задачи
PM MAIL   Вверх
mes
Дата 14.1.2010, 17:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  14.1.2010,  16:15 Найти цитируемый пост)
Тогда при приведении:
1.  компилятор должен определить, где начинается, например, А и положить в указатель адрес на область А.


зачем компилятору адрес, если есть имя.. Пусть линкер думает что и куда соединять и по какому адресу располагать smile


Цитата(Gunslinger @  14.1.2010,  16:15 Найти цитируемый пост)
можно привести указатель с С на указатель не только к ео родителям А, В, а к любому другому. Например, к какому-нибудь Е, который от А и В вообще  не наследует

можно.. закрыв глаза компилятору..но тогда вся ответсвенность лежит на программисте..
если структура будет подходящей (ну а значит у программиста руки не кривые), то все будет работать правильно.
Наследование это  указание компилятору что некая часть различных структур памяти  (то что мы называем объектом) имеет одинаковую организацию
и с ней можно работать одинаково. Благодаря этому указанию С++ позволяет снять заботу с программиста по приведению указателей.

Добавлено через 3 минуты и 14 секунд
Кстати Ваш вопрос (о выборе метода) к наследованию прямого отношения не имеет. Это определяется правилами видимости.




--------------------
PM MAIL WWW   Вверх
mes
Дата 14.1.2010, 17:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



а понял с какой стороны не хватало обзора.. 

вот два примерчика, в обоих один и тот же принцип :
Код

struct A {
 static void f();
};
struct B : A {
};
struct C : B {
 static void f();
};

((A*)NULL)->f();
//  A::f();
((B*)NULL)->f();
//  B::f(); == A::f();
((C*)NULL)->f();
//  C::f();


Код

namespace A
{
   void f( );
}
namespace B {
  using A::f()
}
namespace C {
  using A::f()
}
A::f():
B::f(); // == A::f();
C::f();


и главное нужно понимать, что в примерах НЕТ ни одной функции  с именем f(); 
Мы используем лишь часть имени, потому как о другой части компилятор может сам догадаться..
реально функция называется N::f()  (где N специализация имени).. Т.е область определения входит в состав полного имени.
Так что компилятор  выбирает не какой адрес подставить, а какую специализацию несет имя. (т.е фактически опр. какое полное имя функции)




Это сообщение отредактировал(а) mes - 14.1.2010, 17:51


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 15.1.2010, 11:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Как всегда все оказалось сложнее, чем я думалsmile
Вывод по теме:
если у класса 1 или несколько родителей, то компилятор:
1. не создает копии методов родителей;
2. не располагает методы родителей и наследника в памяти друг за другом -> возможность преобразования указателя с наследника на его родителя обеспечивается... линковщиком?
PM MAIL   Вверх
baldina
Дата 15.1.2010, 11:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



Цитата

1. не создает копии методов родителей;

Более того, любая функция существует лишь в одном экземпляре. Помимо соображений достаточности есть еще одно простое: если используется указатель на функцию, то он должен быть одинаковым во всех частях программы. Значит и функция одна.
При открытом наследовании родительские открытые функции становятся частью интерфейса потомка. Но не частью реализации. И вызов derived::f(), если f() унаследована из base, фактически означает base::f(), т.е. функция одна. mes все это подробно объяснил.

Цитата

2. не располагает методы родителей и наследника в памяти друг за другом -> возможность преобразования указателя с наследника на его родителя обеспечивается... линковщиком? 

располагает как сочтет нужным, как именно - совершенно непринципиально. вообще-то компилятор этим занимается (в пределах единицы компиляции), но современные продвинутые линковщики тоже могут двигать.
а преобразование типа линковщиком не осуществляется, это бред. в общем случае линковщик понятия не имеет о классах. адрес вызова определяет компилятор; в коде уже адрес конкретной функции.
PM MAIL   Вверх
mes
Дата 15.1.2010, 12:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  15.1.2010,  10:16 Найти цитируемый пост)
если у класса 1 или несколько родителей, то компилятор:
1. не создает копии методов родителей;

родители тут вобще не причем. Да и сами классы тоже.
Важны понятия видимости/перекрытия имен ну и соответсвенно scope в котором располагается функция.


Цитата(Gunslinger @  15.1.2010,  10:16 Найти цитируемый пост)
2. не располагает методы родителей и наследника в памяти друг за другом.. 

к памяти это отношения АБСЛЮТНО НЕ имеет, см пример с namespace
важен не адрес функции, а ее Полное Специализированное Имя!

Цитата(Gunslinger @  15.1.2010,  10:16 Найти цитируемый пост)
возможность преобразования указателя с наследника на его родителя обеспечивается... 

указатель тут НЕ причем  !..  преобразование тоже НЕ причем !.. оно относится (в том смысле в каком Вы в этой  теме подразумевали) только для доступа к данным. 
Для методов это "побочный эффект" - просто от типа указателя, зависит scope в котором компилятор начнет искать подходящее имя.
т.е. если указатель  типа B* то p->f() заменится на p->B::f().
когда делаете преобразование меняется и тип объекта к которому хотите применить операцию, ну и соответсвенно  компилятор подставляет нужную специализацию.




Это сообщение отредактировал(а) mes - 15.1.2010, 12:06


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 15.1.2010, 12:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  15.1.2010,  12:04 Найти цитируемый пост)
Важны понятия видимости/перекрытия имен ну и соответсвенно scope в котором располагается функция.

 Важно компилятору? Чтобы сделать преобразование:
Цитата(mes @  15.1.2010,  12:04 Найти цитируемый пост)
т.е. если указатель  типа B* то p->f() заменится на p->B::f().
?




PM MAIL   Вверх
mes
Дата 15.1.2010, 12:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  15.1.2010,  11:22 Найти цитируемый пост)
Важно компилятору? Чтобы сделать преобразование:

нет.. Важно для выбора  метода.. 
Вы рассматриваете преобразование и выбор подходящего метода как одну операцию , а их то две !

Добавлено @ 12:54
Чтоб не путаться дальше  сформируйте вопросы заново, чтоб видно было, с чем Вы уже разобрались, а где ушли в сторону.

Добавлено @ 13:05
Вот я вам составил пример, убрав  все лишнее : методы, классы, наследование и т.д.

Код

namespace A {
    void f(int)  { std::cout << " int " << std::endl; }
}
namespace B {
    void f(char) { std::cout << " char "<< std::endl; }     
}

void test1 ()
{
    using namespace A;
    f(1);     
    f(char());
    f(short());    
    f(int());   
}
void test2 ()
{
    using namespace B;
    f(1);     
    f(char());
    f(short());    
    f(int());
}
void test3 ()
{
    using namespace A;
    using namespace B;
    f(1);     
    f(char());
    f(short());    
    f(int());
}

int main (int argc, char* argv[])
{
     std::cout << std::endl << "test1" << std::endl;
     test1 (); 

     std::cout << std::endl << "test2" << std::endl;
     test2();

     std::cout << std::endl << "test3" << std::endl;
     test3();

  return 0;

}


для начала разберитесь что происходит здесь, а потом уже легко расширите и на классы.
smile

Это сообщение отредактировал(а) mes - 15.1.2010, 13:05


--------------------
PM MAIL WWW   Вверх
mes
Дата 15.1.2010, 13:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



а также почему не работает, если изменить пример :
Код

...

void test ()
{
    f(1);     
    f(char());
    f(short());    
    f(int());   
}

int main (int argc, char* argv[])
{
     std::cout << std::endl << "test" << std::endl;
     using namespace A;
     test (); 
}    


Это сообщение отредактировал(а) mes - 15.1.2010, 13:10


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 15.1.2010, 14:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  15.1.2010,  13:09 Найти цитируемый пост)
void test ()
{
    f(1);     
    f(char());
    f(short());    
    f(int());   
}

Не знаю, что это -- char(). Вроде функция, но char -- ключевое слово, так использовать нельзя. Если это параметр char, то компилятор не поймет, т.к. в пространстве А функции с таким параметром нет.

Цитата(mes @  15.1.2010,  12:50 Найти цитируемый пост)
Чтоб не путаться дальше  сформируйте вопросы заново, чтоб видно было, с чем Вы уже разобрались, а где ушли в сторону.

Я уже запутался... Придется начать сначала.
Что уже известно: 
1. Данные класса группируют в памяти друг за другом ("блоковое" расположение) и у каждого объекта класса -- их своя копия. 
2. Такие блоки связаны со своими методами скрытым параметром this (адресом на блок).
3. Методы класса (и простые функции) не группируются друг за другом и копий не имеют. 
Как?

Добавлено через 3 минуты и 45 секунд
Цитата(mes @  15.1.2010,  13:09 Найти цитируемый пост)
а также почему не работает, если изменить пример :
...
void test ()
{
    f(1);     
    f(char());
    f(short());    
    f(int());   
}

Не известно пространство имен.


Это сообщение отредактировал(а) Gunslinger - 15.1.2010, 15:02
PM MAIL   Вверх
mes
Дата 15.1.2010, 15:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  15.1.2010,  13:59 Найти цитируемый пост)
Не знаю, что это -- char(). Вроде функция, но char -- ключевое слово, так использовать нельзя. Если это параметр char, то компилятор не поймет, т.к. в пространстве А функции с таким параметром нет.

ну так запустите и проверьте..

Цитата(Gunslinger @  15.1.2010,  13:59 Найти цитируемый пост)
1. Данные класса группируют в памяти друг за другом ("блоковое" расположение) и у каждого объекта класса -- их своя копия. 

данные-члены также бывают статические и нестатические. 

1. статические объявляются в классе, но  должны быть определены вне класса .. к объекту класса отношения не имеют.
(для констант есть допуски которые не касаются этой темы )

2. нестатические определяются внутри класса, и все вместе (вместе с нестатическими данными всех подобъектов) образуют общую (не смотря на то что  описаны в разных классах) структуру объекта. Именно на эту структуру и указывает this в нестатических функциях-членах. Она же и определяет размер класса.
("структура" подразумевается не как ключевое слово stuct, a как понятие)

Цитата(Gunslinger @  15.1.2010,  13:59 Найти цитируемый пост)
2. Такие блоки связаны со своими методами скрытым параметром this (адресом на блок).

ну если связанны то точно также как и с другими аргументами. 

лучше сказать, что в функции-члены неявно передается параметр, который для нестатических функций доступен через ключевое слово this и указывает на адрес полученного объекта.

Цитата(Gunslinger @  15.1.2010,  13:59 Найти цитируемый пост)
3. Методы класса (и простые функции) не группируются друг за другом и копий не имеют. 

Что будет представлять в машинном коде функция(-член) мы сказать не можем. Она может быть заинлайнена, да так что от нее не останется и следа, а может состоять из целой череды асм-функций. Гарантируется одно, что адрес функции, где бы его не взяли, будет одним и тем же.

Добавлено через 5 минут и 35 секунд
Цитата(Gunslinger @  15.1.2010,  13:59 Найти цитируемый пост)
Не известно пространство имен.

угу.. точнее потому что подходящей функции с таким именем нет в области видимости.



Это сообщение отредактировал(а) mes - 15.1.2010, 15:30


--------------------
PM MAIL WWW   Вверх
baldina
Дата 15.1.2010, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 3433
Регистрация: 5.12.2007
Где: Москва

Репутация: 32
Всего: 101



mes, мне кажется, Вы даете топикстартеру ответы на вопросы, которые ему даже не приходят в голову. Представляю, какая уже каша из понятий видимости, наследования и проч...  smile 

Вообще мне кажется, стоит начать с того, что данные и код в памяти компьютера могут быть (и как правило находятся) в различных, удаленных друг от друга блоках памяти. Программист имеет дело с семантикой, описанной в стандарте, т.е. с некоей виртуальной машиной С++, а машинный код может получиться разным в зависимости от реализации компилятора. Есть наиболее популярные реализации, есть требования стандарта (типа последовательного расположения в памяти элементов vector), накладывающие ограничения на реализацию, но не более того.
PM MAIL   Вверх
Gunslinger
Дата 15.1.2010, 16:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  15.1.2010,  15:28 Найти цитируемый пост)
ну так запустите и проверьте..

Хм, не видит char(). Выводит int.

Цитата(mes @  15.1.2010,  15:28 Найти цитируемый пост)
ключевое слово this и указывает на адрес полученного объекта.

Уточнение: полученный объект == копия данных класса? (Раньше объект воспринимал монолитно: объект - это и данные, и методы(когда не знал, что методы существуют в одном экземпляре))

Цитата(mes @  15.1.2010,  15:28 Найти цитируемый пост)
статические объявляются в классе, но  должны быть определены вне класса

Код

class A{
      static int n1;
}

class B: public A{
 public: 
      B(int f){
             A::n1=f;}
}

B obj1(12);
//либо
А.n1=12;

Это?


Это сообщение отредактировал(а) Gunslinger - 15.1.2010, 17:29
PM MAIL   Вверх
mes
Дата 15.1.2010, 19:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  15.1.2010,  15:49 Найти цитируемый пост)
Хм, не видит char(). Выводит int.

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

Цитата(Gunslinger @  15.1.2010,  15:49 Найти цитируемый пост)
полученный объект == копия данных класса? 

зависит от способа передачи:
  если по значению то копия
  если по имени/ссылке то оригинал



Цитата(Gunslinger @  15.1.2010,  15:49 Найти цитируемый пост)
объект - это и данные 


уточнение объект (инстанция класса)  это совокупность всех не статических  данных-членов  как самого класса, так и всех его подклассов 
(и некой служебной информации в случае обладания виртуальными функциями)

Цитата(Gunslinger @  15.1.2010,  15:49 Найти цитируемый пост)
когда не знал, что методы существуют в одном экземпляре)

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

A1 obj; obj.f();

мы вызвали НЕ функцию f объекта obj,
а вызвали функцию f класса A и передали ей объект obj как параметр.
( то что получит функция зависит от способа передачи.. то есть прежде чем стать аргументом this может произойти как  простое копирование (при передаче по значению), так и преобразование типа .. но это опять другая тема)








Это сообщение отредактировал(а) mes - 15.1.2010, 20:00


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 15.1.2010, 21:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  15.1.2010,  19:59 Найти цитируемый пост)
мы вызвали НЕ функцию f объекта obj,
а вызвали функцию f класса A и передали ей объект obj как параметр.

Это я понимаю.

Цитата(mes @  15.1.2010,  19:59 Найти цитируемый пост)
это про статические данные корректно говорить что они существуют в единственном экземпляре.
а когда такое про функции  - то слух режет. Дело в том смысле какой Вы вкладываете.

Просто хотел подчеркнуть, что:
Код

class A{
  int data1;
  int data2;
 public:
    int a1(){};
    int a2(){};
}

A obj1;
A obj2;
.........
A objn;    
 
Компилятор создает:
Код

namespace A{
   int a1(){};
   int a2(){};
}

struct obj1{
int data1;
int data2;
}

struct obj2{
int data1;
int data2;
}

.....



Это сообщение отредактировал(а) Gunslinger - 15.1.2010, 21:46
PM MAIL   Вверх
mes
Дата 15.1.2010, 22:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  15.1.2010,  20:45 Найти цитируемый пост)
Просто хотел подчеркнуть, что:

у Вас либо куча опечаток в коде, либо Вы все таки не до конца поняли...



--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 16.1.2010, 09:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  15.1.2010,  22:08 Найти цитируемый пост)
у Вас либо куча опечаток в коде, либо Вы все таки не до конца поняли...

Значит не до конца... Что в коде не верно представляю?
PM MAIL   Вверх
mes
Дата 16.1.2010, 14:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



ну прежде всего в первом коде идет создание N объектов, а во 2м описание N структур объектов.
ну и мелочь : аналог метода описанный в  namespace должен принимать (скрытый) параметр на объект.
Вот  расширенный пример того что Вы писали:
Код

class A 
{
      char c;
   public:
    A () {c = 'A'; }
     void  f () { std::cout<< c; }
};
class B 
{
      char c;
   public:
     B() { c= 'B'; }
     void  f () { std::cout<< c; }
};
int main () {
A  a;
B  b;

a. f();
b.f();
b.A::f();
}


может быть представлен  в таком условном  коде :
/* примечания :
 в квадратных скобках указываются скрытые параметры (при чтение кода не учитывать так как не являются разделительными)
 со знаком $  обозначены внутренние действия компилятора
 указание прав доступа не учитывается..
 код не отнсящийся на прямую к примеру (std::cout) представлен без изменений
*/

Код


struct A [::this_t] {
  char [A::] c;   
};

struct B [::this_t] {
  char [A::] c;
  char [B::] c;
};

// дoбавляем компил-тайм правило для компилятора о возможности преобразования по наследию :
$cast_rule: B --> A = true

void [A::] f ( [A::this_t* this] ) { std::cout << this->[A::]c; }
void [B::] f ( [B::this_t* this] ) { std::cout << this->[B::]c; }

int main () {

 A [::this_t]  a;
 B [::this_t]  b;

 [A::] f ( [&a] );
 [B::] f ( [&b] );
 [A::] f ( [&b] );
}
   

надеюсь пример не запутает Вас eще сильней..
старался сделать как можно понятнее..
smile

Это сообщение отредактировал(а) mes - 19.1.2010, 20:08


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 18.1.2010, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  16.1.2010,  14:38 Найти цитируемый пост)
$cast_rule: B --> A = true

В верхнем коде класс В не наследует от А. Вы забыли дописать или все верно?
PM MAIL   Вверх
mes
Дата 18.1.2010, 11:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  18.1.2010,  09:07 Найти цитируемый пост)
В верхнем коде класс В не наследует от А. Вы забыли дописать или все верно? 

Вы ж не думаете, что принятая форма записи в С++ - единственная возможная ?
часть B повторяет структуру А ? есть правило приведения от наследника к базовому ? Ну значит условно наследуется.  ;)
Я специально выбрал вариант, чтоб на разнице показать что есть наследование по сути.
smile

А вообще компилятор прежде, чем компилить в объектный файл, приводит текст программы в удобное для него состояние.
Rаньше С++ компилятор был вообще простым С-кодогенератором. Т.е. из С++ программы генерил С-код (в котором как известно нет инструмента наследования).
Ну так будем считать, что приведенный пример одна из стадий (препроцессор) такого кодогенератора, которая разворачивает код связанный с наследованием в условный с-структурный вид.
smile

Это сообщение отредактировал(а) mes - 18.1.2010, 11:28


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 18.1.2010, 16:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  18.1.2010,  11:12 Найти цитируемый пост)
Вы ж не думаете, что принятая форма записи в С++ - единственная возможная ?

Кроме с++ной записи о других не знаю. Т.е. вы описали то же наследование? А то у меня чуть крыша не поехалаsmile А так почти все понятно --  ваш высокоуровневый код с namespace, но уже в низкоуровневом исполнении. Вот эта строка только не дается:
Код

[A::] f ( [static_cast<A*>(&b)] );


Код

struct B [::this_t] {
  char [A::] c;
  char [B::] c;
};

  char [A::] c; -- это вроде ссылки или указателя на структуру А?
  Как происходит подобное приведение: определяется, где в структуре В находится А::с? 


PM MAIL   Вверх
mes
Дата 18.1.2010, 18:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  18.1.2010,  15:21 Найти цитируемый пост)
Т.е. вы описали то же наследование?

Будет точнее сказать что я раскрыл классы с наследованием на простые структуры с той же зависимостью.

Цитата(Gunslinger @  18.1.2010,  15:21 Найти цитируемый пост)
Как происходит подобное приведение: определяется, где в структуре В находится А::с? 

нет.. Зачем определяться если структура наследник, содержит все данные предка в той же последовательности с нулевым (в нашем случае) смещением.



--------------------
PM MAIL WWW   Вверх
mes
Дата 18.1.2010, 18:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  18.1.2010,  15:21 Найти цитируемый пост)
Вот эта строка только не дается:

static_cast - это безопасное приведение. Для того чтоб наш наследник мог конвертиться
мы установили 
Цитата(mes @  16.1.2010,  13:38 Найти цитируемый пост)
$cast_rule: B --> A = true

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

smile


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 19.1.2010, 12:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Код

[A::] f ( [static_cast<A*>(&b)] );

Благодаря скрытому параметру this каждый метод определяет, где находятся данные, с которыми он будет работать.. 
Тогда такое приведение значит, что this B меняется на this, где расположена struct A?

Это сообщение отредактировал(а) Gunslinger - 19.1.2010, 12:50
PM MAIL   Вверх
mes
Дата 19.1.2010, 20:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  19.1.2010,  11:48 Найти цитируемый пост)
Тогда такое приведение значит, что this B меняется на this, где расположена struct A?

убрал я из примера static_cast -  для сути он не нужен.

имя "A::f" логически идеентично "A_f", а "::" просто специфичный разделитель, позволяющий программисту записывать имена в неполной форме.
(до полной дорабатывает компилятор)

Хотя приведенное еще не полное имя функции, а специализированное.. - т.е. в имя включена зона в которой его определили.
полное включает в себя еще типы параметров, благодаря чему и становится возможна перегрузка.




--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 20.2.2010, 14:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  19.1.2010,  20:14 Найти цитируемый пост)

имя "A::f" логически идеентично "A_f", а "::" просто специфичный разделитель, позволяющий программисту записывать имена в неполной форме.
(до полной дорабатывает компилятор)

Хотя приведенное еще не полное имя функции, а специализированное.. - т.е. в имя включена зона в которой его определили.
полное включает в себя еще типы параметров, благодаря чему и становится возможна перегрузка.

Например, из кода
Код

struct A [::this_t] {
  char [A::] c;   
};

Компилятор делает нечто вроде A_char_c? Т.е. это то, как «выглядит» переменная на, практически, самом нижнем уровне? Еще одна вещь, над которой я раньше не задумывался..


Это сообщение отредактировал(а) Gunslinger - 20.2.2010, 15:01
PM MAIL   Вверх
mes
Дата 20.2.2010, 15:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  20.2.2010,  13:54 Найти цитируемый пост)
Компилятор делает нечто вроде A_char_c?

ага, в принципе так, только в более удобном для него виде. И с функциями тоже самое.

Добавлено через 3 минуты и 4 секунды
Цитата(Gunslinger @  20.2.2010,  13:54 Найти цитируемый пост)
Т.е. это то, как «выглядит» переменная на, практически, самом нижнем уровне? 

1. не переменная, а ее имя.
2. на самом низшем имя заменяется на значения (например смещения), поэтому не на самом низшем, а после раскрытия всех скоупов (пространств имен)




--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 20.2.2010, 17:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  20.2.2010,  15:32 Найти цитируемый пост)
ага, в принципе так, только в более удобном для него виде. И с функциями тоже самое.

Таким образом компилятор реализует и различные ограничители, вроде private, protected, namespace, const --  всего лишь добавляет к имени переменной\метода соответствующие  "пометки"? 

Это сообщение отредактировал(а) Gunslinger - 20.2.2010, 17:55
PM MAIL   Вверх
mes
Дата 20.2.2010, 20:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  20.2.2010,  16:55 Найти цитируемый пост)
Таким образом компилятор реализует и различные ограничители, вроде private, protected, namespace, const --  всего лишь добавляет к имени переменной\метода соответствующие  "пометки"? 


Ага, определение характеристик сущности в любом нужно-произвольном месте основывается на "пометках", которые компилятор запоминает для каждой сущности в процессе парсинга кода.

Единственное, что не все пометки отражаются на имени. Полное имя нужно линкеру для связки - и на тот момент уже нет ни типов, ни скоупов, есть только имя.
Компилятору необходимо гораздо больше информации (например тип, размер, право доступа), поэтому все "пометки" он хранит в специальных внутренних структурах. Как именно он хранит, каждый компилятор решает сам.
smile




--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 20.2.2010, 22:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  20.2.2010,  20:42 Найти цитируемый пост)

Единственное, что не все пометки отражаются на имени. 

static переменные\методы, например? Существуют ведь в одной копии -- линкер вроде запутаться не должен.
По поводу Вашего предыдущего примера кода.
Код

struct A [::this_t] {
  char [A::] c;   
};
struct B [::this_t] {
  [U]char [A::] c;[/U]
  char [B::] c;
};

void [A::] f ( [A::this_t* this] ) { std::cout << this->[U][A::]c[/U]; }
void [B::] f ( [B::this_t* this] ) { std::cout << this->[B::]c; }

int main () {
A  a;
B  b;
a. f();
b.f();
b.A::f[U]()[/U];
}

b.A::f() -- вроде вызывается для объекта b, но у метода адрес на данные объекта а. Получается, f() возьмет не переменную "c" наследника, родителя: а.с?   
PM MAIL   Вверх
mes
Дата 20.2.2010, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  20.2.2010,  21:08 Найти цитируемый пост)
static переменные\методы, например? Существуют ведь в одной копии -- линкер вроде запутаться не должен.

про запутаться :
Код

void f(char c);
void f(int c);

какую f вызвать из этих линкеру было бы не понятно, поэтому для него обоим функциям 
задается вид типа например такого :
Код

fn1f4char;
fn1f3int;

 где в нашем случае для разделителя выбрано число показывающее кол-во символов до следующего разделителя.

второй вариант, экспортировать имя функции в стиле, тогда у функции будет "нормальное" имя, но такая функция лишиться возможности перегрузки и расположения не в глобальном пространстве имен.

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

Цитата(Gunslinger @  20.2.2010,  21:08 Найти цитируемый пост)
 Получается, f() возьмет не переменную "c" наследника, родителя: а.с?

по адресу b есть данные как наследника , так и родителя,
Цитата(Gunslinger @  20.2.2010,  21:08 Найти цитируемый пост)
 Получается, f() возьмет не переменную "c" наследника, родителя: а.с?

да, так как мы указали явно что надо использовать функцию A::f будет вызвана именно она, а соответсвенно использоваться будет дата_член A::c.
smile


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 21.2.2010, 10:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  20.2.2010,  22:55 Найти цитируемый пост)

да, так как мы указали явно что надо использовать функцию A::f будет вызвана именно она, а соответсвенно использоваться будет дата_член A::c.

В b есть копия переменной-родителя, однако ни метод b.f(), ни b.a::f() не могут к ней обратиться: либо к b.c, либо к a.c. Как же тогда обратиться к [A::]с в наследнике? Знаю только, как в ActionScript3 такое сделано, но там все просто: super.наследованная_переменная.

PM MAIL   Вверх
mes
Дата 21.2.2010, 11:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  21.2.2010,  09:37 Найти цитируемый пост)
но там все просто: super.наследованная_переменная.

а в паскaле есть служебное слово inherited, ну а в С++ никаких служебных слов для этого не надо, достаточно указать специализированное имя переменной.
smile
Код

struct A
{
  int i;
  int j;
};
struct B : A
{
   int i;
   void f ()
   {
       i++;  // то же самое что и  B::i++;

       A::i++; // а вот обращение к переменной предка

       j++;  // ну а тут сразу обращаемся к переменной предка, так как в наследнике это имя не перекрыто
               // т.е аналогично A::j++;
   } 
};

smile

Это сообщение отредактировал(а) mes - 21.2.2010, 11:05


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 21.2.2010, 12:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  21.2.2010,  11:03 Найти цитируемый пост)
       A::i++; // а вот обращение к переменной предка

Это обращение к переменной struct A или унаследованной, которая в struct B? Они ведь принадлежат к разным классам -- в наследнике B содержится копия A.i.
 
PM MAIL   Вверх
mes
Дата 21.2.2010, 13:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  21.2.2010,  11:30 Найти цитируемый пост)
Это обращение к переменной struct A или унаследованной

ну так в самом начале же разбирали, что объект включает в себя все дата-члены как своего класса, так и всех предков.
то есть объект класса B имеет следующие дата-члены :
Код

A::i
B::i
B::j


так как с именем i  две переменных, то имя определенное в наследнике скрывает имя определенное в предке, поэтому если необходимо обратиться к последнему, то необходимо уточнение (специализация имени).  Ну а если например Вы б обратились например к переменной x, то так как их нет в описании класса и его предков, то компилятор предположил бы что обращаетесь к "наружней" (не к члену) переменной и начал бы искать подходящую там.

Пример из жизни. Допустим Вы студент, и в Вашем классе есть Коля. Когда Вы говорите о нем со своими однокурсниками, то всем понятно о ком речь.
Но на параллельном курсе тоже есть Коля, и когда Вы хотите упомянуть его, то должны уточнить о ком именно идет речь. А вот например парень с именем Аквакате только один на весь институт, и ни у кого сомнения не возникнет о ком идет речь, даже не уточняя. 
smile

В общем язык программирования это тоже язык, и если в ЯНУ все плоско и каждая конструкция  имеет только одно соответствие, то ЯВУ позволяет себе "такую же" игру слов как и разговорные язык и смысл конструкции не очевиден без знания контекста. 
для Си обычно приводят пример : что есть i * j ?;




--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 23.2.2010, 10:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  21.2.2010,  13:22 Найти цитируемый пост)
ну так в самом начале же разбирали, что объект включает в себя все дата-члены как своего класса, так и всех предков.

Так ведь включает "копию", а не оригинал. Оригинал как принадлежал родителю, так и принадлежит... Вначале темы думал, что при наследовании создаются и копии методов, которые "перенаправляются" на унаследованные дата-члены. Оказалось ошибался -- копии методов не создаются и не "перенаправляются", а продолжают указывать на дата-члены родителя. Но теперь куча других вопросов:
1. Как обратиться к унаследованным переменным?
2. Если в родителе реализовывался какой-нибудь механизм (методы выполняли и писали состояние в дата-члены), то, если в наследнике предварительно не выполнить эти механизмы, то можно поломать логику работы наследника.. Как тогда быть, методы родителя же "направлены" на дата-члены родителя?
PM MAIL   Вверх
mes
Дата 23.2.2010, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  23.2.2010,  09:45 Найти цитируемый пост)
Так ведь включает "копию", а не оригинал. 

Ну вот приехали.. smile  smile 
разберем на примере из жизни :  Млекопитающего, как базового класса и волка как наследника.
Цитата

Млекопитающие — класс позвоночных животных, основными отличительными особенностями которых являются живорождение ... и вскармливание детёнышей молоком. ... ... ...

Цитата

Волк, серый волк, обыкновенный волк (лат. Canis lupus) — хищное млекопитающее семейства псовых. ... ... ...

Мы имеем два описания, притом второе включает в себя первое по принципу наследования.  Фактически это говорит, что все что справедливо для объекта второго описания действительно и все что описано в первом.

Описание и есть класс, при том 
первое описание -  абстрактный класс, так как по нему не понятно какой именно объект имеется ввиду, и обладает недостаточной информацией для "построения" объекта данного класса
второе описание - конкретный класс, так как обладает достаточной информацией для "построения" объекта данного класса.

А вот и сам обьект, изображен на картинке :
user posted image
Как видно этому объекту соответствуют оба описания. В программировании говорится, что поддерживает оба интерфейса,
что другими словами означает, что  поведение объекта справедливо для обоих описаний. 

Также очевидно, что описаний может быть намного больше.

Теперь хотелось бы уточнить сказанное в Вашей цитате, копии чего из класса содержит объект  ?!  smile 







Это сообщение отредактировал(а) mes - 23.2.2010, 13:22


--------------------
PM MAIL WWW   Вверх
mes
Дата 23.2.2010, 11:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  23.2.2010,  09:45 Найти цитируемый пост)
Вначале темы думал, что при наследовании создаются и копии методов, которые "перенаправляются" на унаследованные дата-члены. Оказалось ошибался -- копии методов не создаются и не "перенаправляются", а продолжают указывать на дата-члены родителя. Но теперь куча других вопросов:

вот Вам еще один пример
Код

struct A 
{
    int i;    
    void show_i () { std::cout << "A::i == " << i << std::endl; }
} a;

struct B : A
{
    int i;
    void show_i () { std::cout << "B::i == " << i << std::endl; }
} b;

int main()
{
  std::cout << std::endl << "rtest with a :" << std::endl;
  a.i =5; 
  a.show_i();
  a.A::show_i();
  
  std::cout  << std::endl << "test with b :" << std::endl;
  b.i=7;
  b.show_i();

  b.A::i = 12;
  b.B::i = 17;
  b.A::show_i();  
  b.B::show_i();

  b.show_i();
}


Добавлено через 4 минуты и 30 секунд
теперь построчный перевод вышеприведенного примера, но все методы заменены на обычные функции.
Код

struct A 
{
    int i;    
} a;

struct B : A
{
    int i;

} b;

void A_show_i (A& _this) { std::cout << "A::i == " << _this.i << std::endl; }
void B_show_i (B& _this) { std::cout << "B::i == " << _this.i << std::endl; }    
    
int main()
{
  std::cout << std::endl << "rtest with a :" << std::endl;
  a.i =5; 
  A_show_i(a);
  A_show_i(a);
  
  std::cout  << std::endl << "test with b :" << std::endl;
  b.i=7;
  B_show_i(b);

  b.A::i = 12;
  b.B::i = 17;
  A_show_i(b);  
  B_show_i(b);

  B_show_i(b);

}


Добавлено через 10 минут и 1 секунду
теперь тот же пример при отсутствии в языке механизма наследования
Код


struct A 
{
    int i;    
} a;

struct B 
{
    int A_i;
    int i;

} b;

void A_show_i (void * _this) { std::cout << "A::i == " << (*(A*)_this).i << std::endl; }

void B_show_i (void * _this) { std::cout << "B::i == " << (*(B*)_this).i << std::endl; }    

    
int main()
{
  std::cout << std::endl << "rtest with a :" << std::endl;
  a.i =5; 
  A_show_i(&a);
  A_show_i(&a);
  
  std::cout  << std::endl << "test with b :" << std::endl;
  b.i=7;
  B_show_i(&b);

  b.A_i = 12;
  b.i = 17;
  A_show_i(&b);  
  B_show_i(&b);

  B_show_i(&b);
}

за соответсвие передаваемых типов отвечает не компилятор, а программист.

Это сообщение отредактировал(а) mes - 23.2.2010, 11:58


--------------------
PM MAIL WWW   Вверх
mes
Дата 23.2.2010, 12:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



опять тот же пример, но с отсутствием в языке механизма стуктур
Код

// struct A
typedef char A [ sizeof(int) // i (A_i)
               ];              
// struct B            
typedef char B [ sizeof(A)   // A
               + sizeof(int) // i (B_i)
               ];                        

int& A_i(char * _this) { return *(int*)(_this + 0); }
int& B_i(char * _this) { return *(int*)(_this + sizeof (A) + 0); }

void A_show_i (char * _this) { std::cout << "A::i == " << A_i(_this) << std::endl; }
void B_show_i (char * _this) { std::cout << "B::i == " << B_i(_this) << std::endl; }    

A a; B b;
   
int main()
{
  std::cout << std::endl << "test with a :" << std::endl;
  A_i (a) =5; 
  A_show_i(a);
  A_show_i(a);
  
  std::cout  << std::endl << "test with b :" << std::endl;
  B_i (b) =7;
  B_show_i(b);

  A_i(b) = 12;
  B_i(b) = 17;
  
  A_show_i(b);  
  B_show_i(b);

  B_show_i(b);

}


Добавлено @ 12:17
думаю примеров Вам хватит, и в них вроде бы отражены вплоть до низшего уровня все вопросы этой темы. smile

Это сообщение отредактировал(а) mes - 23.2.2010, 13:19


--------------------
PM MAIL WWW   Вверх
Gunslinger
Дата 28.2.2010, 09:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 842
Регистрация: 30.12.2006
Где: Астрахань

Репутация: 1
Всего: 3



Цитата(mes @  23.2.2010,  12:15 Найти цитируемый пост)
Код

// struct A
typedef char A [ sizeof(int) // i (A_i)
               ];              
// struct B            
typedef char B [ [U]sizeof(A)[/U]   // A
               + sizeof(int) // i (B_i)
               ];                        
int& A_i(char * _this) { return *(int*)([U]_this + 0[/U]); }
int& B_i(char * _this) { return *(int*)([U]_this + sizeof (A) + 0[/U]); }


Большое спасибо за терпеливое разъяснение и за пример с отсутствием структур -- очень доходчивый. Теперь понятно. Метод родителя можно "перенаправить" на унаследованные дата-члены -- это возможно за счет того, что в наследник добавляются сначала дата-члены родителя, а потом уже наследника. При такой последовательности методы родителя "знают" смещение "своих" унаследованных дата-членов.
А как быть с множественным наследованием?
Если class C: A, B, дата-члены В будут располагаться после дата-членов А, и тогда методы В будут "смотреть" не туда -- смещение будет неверным. Компилятор создает какой-нибудь дополнительный механизм?



Это сообщение отредактировал(а) Gunslinger - 28.2.2010, 09:47
PM MAIL   Вверх
mes
Дата 28.2.2010, 13:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  28.2.2010,  08:45 Найти цитируемый пост)
Метод родителя можно "перенаправить" на унаследованные дата-члены -- это возможно за счет того, что в наследник добавляются сначала дата-члены родителя, а потом уже наследника. При такой последовательности методы родителя "знают" смещение "своих" унаследованных дата-членов

ура ! smile  

Цитата(Gunslinger @  28.2.2010,  08:45 Найти цитируемый пост)
А как быть с множественным наследованием?
Если class C: A, B, дата-члены В будут располагаться после дата-членов А, и тогда методы В будут "смотреть" не туда -- смещение будет неверным. Компилятор создает какой-нибудь дополнительный механизм?

 smile , он добавляет еще дополнительное смещение вторично-унаследованных классов.

Это сообщение отредактировал(а) mes - 28.2.2010, 14:22


--------------------
PM MAIL WWW   Вверх
mes
Дата 28.2.2010, 14:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


любитель
****


Профиль
Группа: Участник Клуба
Сообщений: 7954
Регистрация: 14.1.2006

Репутация: 144
Всего: 250



Цитата(Gunslinger @  28.2.2010,  08:45 Найти цитируемый пост)
и за пример с отсутствием структур -- очень доходчивый.

вот Вам тогда еще один демонстрационный пример без структур, с учетом механизма множественного наследования.
Код

// struct A { int i };
typedef char A [ sizeof(int) // i (A_i)
               ];              
int& A_i(char * _this) { return *(int*)(_this + 0); }

// struct B : A { i };
typedef char B [ sizeof(A)   // A
               + sizeof(int) // i (B_i)
               ];                        
int&  B_i(char * _this) { return *(int*)(_this + sizeof (A) + 0); }
char* B_A(char * _this) { return _this + 0; }

// struct AB : A, B {};
typedef char  AB [ sizeof(A)   // A
                 + sizeof(B)   // B
                 ];
char* AB_A(char * _this) { return _this + 0; }
char* AB_B(char * _this) { return _this + sizeof(A); }

int main ()
{
    A a; B b; AB ab;

    A_i(a) = 1;                // a.i;

    A_i(B_A(b)) = 2;           // b.A::i =2;
    B_i(b) = 22;               // b.i=22;

    A_i(AB_A(ab)) = 3;         // ab.A::i = 3;
    B_i(AB_B(ab)) = 33;        // ab.B::i = 33; 
    A_i(B_A(AB_B(ab))) = 333;  // ab.B::A::i = 333; 
 
    std::cout << "a.i == "        << A_i(a)             << std::endl
              << "b.i == "        << B_i(b)             << std::endl              
              << "b.A::i == "     << A_i(B_A(b))        << std::endl
              << "b.B::i == "     << B_i(b)             << std::endl
              << "ab.A::i == "    << A_i(AB_A(ab))      << std::endl
              << "ab.B::i == "    << B_i(AB_B(ab))      << std::endl
              << "ab.B::A::i == " << A_i(B_A(AB_B(ab))) << std::endl;
}

P.S. в примере специально использовано двойное унаследование класса A классом AB () (прямое и косвенное посредством класса B), 
что делает пример не соответствующим правилам С++ из за появления неопределенностей преобразования (в нашем случае работает из за явного указания нужного преобразования), но имхо так лучше для понимания происходящего.


Это сообщение отредактировал(а) mes - 28.2.2010, 15:44


--------------------
PM MAIL WWW   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1382 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.