Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Порядок построения классов (http://forum.oszone.net/showthread.php?t=135056)

pva 18-03-2009 09:20 1066962

Порядок построения классов
 
Где можно почитать про порядок построения классов (с виртуальными функциями)? Пример:
Код:

struct A
{
  virtual void foo() {cout << "A::foo()\n";}
}

struct C
{
  C(A& a) {a.foo();}
}

struct B : A, C
{
  B() : A(), C(*this)
  {
  }

  void foo() {cout << "B::foo()\n";}
}

что по правилам должно появиться на экране, A::foo(), B::foo() или какая-нить ошибка, что класс недостроен?

Alan85 18-03-2009 19:16 1067547

Цитата:

Цитата pva
virtual void foo() {cout << "A::foo()\n";} »

может я чтото уже подзабыл из классов си++ но член класса объявленый виртуальным не может иметь реализацию тут же.
и объявление класса должно быть начинатся с class <name> . Почитать можно в любой более менее нормальной книге по Си++ . Ну а про классы в своей библиотеке нашел "Павловская Т. C++ Объектно-ориентировочное программирование. Практикум"

pva 19-03-2009 07:34 1067917

Цитата:

Цитата Alan85
не может иметь реализацию тут же »

Почему нет? классический пример из книги страуструпа:
Код:

class shape_t
{
public:
  virtual ~shape_t() {}
}

Методы, реализованные в описании раскрываются inline когда могут (если не могут, то не inline)
Цитата:

Цитата Alan85
должно быть начинатся с class <name> »

struct - это тоже класс (любой тип данных есть класс для C++)
Цитата:

Цитата Alan85
Павловская Т. C++ Объектно-ориентировочное программирование. Практикум »

Есть ссылка на "скачать в интернете"?

Alan85 19-03-2009 08:36 1067946

Цитата:

Цитата pva
struct »

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

pva 19-03-2009 10:18 1068058

Цитата:

Цитата Alan85
фишки как private. »

не верю:
Код:

struct A
{
private:
  int _priv_data;
};

вполне собирается любым компилятором C++. Ссылку на книжку не пока могу дать
Более того, даже int есть класс, а у него даже и методов то нет...

Alan85 19-03-2009 19:25 1068604

да, извини, согласен - давно классами в сях не баловался. А верхний пример будет откомпилирован и выведет A::foo(), B::foo() если немного подправить синтаксис (точки с запетой между реализациями). Только хоть используй virtual тут хоть нет - результат тот же.
Код:

#include <iostream>
using namespace std;
class A
{
  public:
  void foo() {cout << "A::foo()\n";}
}    ;
class  C
{
 public:
  C(A& a) {a.foo();}
}  ;

class B : A, C
{
 public:
  B() : A(), C(*this){/**/}
  void foo() {cout << "B::foo()\n";}
}  ;
main()
{
  B b;
  b.foo();
  cin.get();
}


Alan85 19-03-2009 19:50 1068638

Код:

#include <iostream>
using namespace std;
class A
{
  public:
  virtual void foo() {cout << "A::foo()\n";}
}    ;
class  C
{
 public:
  C(A& a) {a.foo();}
}  ;

class B : public A
{
 public:
  void foo() {cout << "B::foo()\n";}
}  ;
main()
{
  B* b=new B();
  A *a=b;
  a->foo();
  b->foo();
  cin.get();
}

а тут слово virtual имеет значение. Тут типичный случай полиморфизма - объект A подменяет свои виртуальные функции функциями из объекта B.

pva 20-03-2009 22:29 1069808

Цитата:

Цитата Alan85
Только хоть используй virtual тут хоть нет - результат тот же. »

вот пример когда есть отличия:
Код:

#include <iostream>
using namespace std;
class A
{
  public:
  void foo() {cout << "A::foo()\n";}
  // функция test_foo не знает, какой именно класс передан аргументом.
  // она просто получила некоторый интерфейс, одинаковый для всех наследников
  friend test_foo(A& a) {a.foo();}
}    ;
class  C
{
 public:
  C(A& a) {a.foo();}
}  ;

class B : A, C
{
 public:
  B() : A(), C(*this){/**/}
  void foo() {cout << "B::foo()\n";}
}  ;
main()
{
  A a;
  B b;
  test_foo(a); // вызов одной функции с разными реализациями foo()
  test_foo(b);
  cin.get();
}

Внимание вопрос! в классе B функция foo вызывается 2 раза. Каждый раз результаты разные.
Цитата:

Цитата Alan85
a->foo();
b->foo(); »

Испльзования класса хранилища (auto или в свободной памяти) не влияет на правила полиморфизма и построения классов, поэтому через operator new() и указатели не было смысла переделывать
Цитата:

Цитата Alan85
A подменяет свои виртуальные функции »

Это то понятно, это на случай, когда оно всё гладко. А вот рассмотрим случай использования недостроенного класса. Рассмотрим конструктор класса (пример сделан специально, чтобы достигнуть нужного эффекта)
Код:

struct B : A, C
{
  // порядок вызова:
  // 1. A::A()
  // 2 С::C(A&)  - подкласс A уже построен, но B:A,C ещё нет
  // 3 тело B::B()
  B() : A(), C(*this)
  {
  }

  void foo() {cout << "B::foo()\n";}
}

Верно ли, что по правилам C++ в случае использования недостроенного класса с виртуальными функциями будут использоваться реализации уже достроенных подклассов либо, в случае использования чистых виртуальных функций, выводится сообщение об ошибке на усмотрение компилятора (например обращение по адресу 0x00000000)
~либо~
Верно ли что использовать недостроенные классы категорически нельзя, реализация поведения остаётся на усмотрение компилятора.
Я ни того, ни другого утверждения ещё не встречал

Alan85 20-03-2009 23:25 1069855

Цитата:

Цитата pva
в случае использования недостроенного класса »

наверно ты имеешь ввиду абстрактный класс.
Код:

class A  //абстрактный
{
  public:
  virtual void foo()=0;
}    ;

То тогда вылетит со свистом так как в в конструкторе C(A& a) {a.foo();} передается B которое еще не создано (после C будет ) что значит B::foot() еще неизвестно (не построена таблица виртуальных функций).
Но стоит только заменить класс A обратно с реализацией функции (она сразу вносится в таблицу виртуальных функций) все отлично - C(A& a) {a.foo();} хоть и принимает B но в таблице не найдя для нее реализации B::foo() передает выше - A::foo().
Я не утверждаю что это истина и верно на всех компиляторах хотя логически должно.

pva 22-03-2009 17:44 1071131

Цитата:

Цитата Alan85
наверно ты имеешь ввиду абстрактный класс. »

Я имел ввиду именно НЕДОСТРОЕННЫЙ класс С РЕЛИЗАЦИЕЙ (когда непонятно, как должна себя вести софтина)

Alan85 22-03-2009 18:03 1071150

Тогда я чтото не пойму :
Код:

struct A
{
  virtual void foo() {cout << "A::foo()\n";}
}

struct C
{
  C(A& a) {a.foo();}
}

struct B : A, C
{
  B() : A(), C(*this)
  {
  }

  void foo() {cout << "B::foo()\n";}
}

По каким критериям он не достроен и одновременно с реализацией. По-моему вполне достроен и реализован.

pva 23-03-2009 07:37 1071634

В конструктор C передаётся часть недостроенного класса B с собственной реализацией виртуальных функций (*this)

Alan85 23-03-2009 07:50 1071641

В конструкторе передается не сам не достроенный объект а его указатель типа B. В самое классе C он преобразуется в класс A (он же подкласс его) что дает a.foo() корректно. Вот вопрос что будет если сделать так C(B& b) {b.foo();} - надо будет дома проверить :)

pva 23-03-2009 14:36 1072046

Цитата:

Цитата Alan85
если сделать так C(B& b) {b.foo();} »

С этим как раз понятно, в лучшем случае слетит ибо используем неинициализированную память с мусором.
Цитата:

Цитата Alan85
(он же подкласс его) что дает a.foo() корректно »

a.foo() - виртуальным метод, имеющий реализации A::foo() и B::foo(). Например:
Код:

struct A
{
  virtual void foo() {cout << "A::foo()\n";}
};

struct C
{
  C(A& a) {test(a);}

  void test(A& a)
  {
    clog << "C::test with &a=" << &a << ", this=" << this << "\n";
    a.foo();
  }
};

struct B : A, C
{
  B() : A(), C(*this)
  {
    test(*this);
  }

  void foo() {cout << "B::foo()\n";}
};

С одними и теми же исходными данными получаем разный результат. Потому что первый раз вызов C::test произойдёт когда формально B ещё не достроен
Код:

C::test with &a=1245060, this=1245064
A::foo()
C::test with &a=1245060, this=1245064
B::foo()

Это особенность компилятора или стандарт с++ такой?


Время: 23:45.

Время: 23:45.
© OSzone.net 2001-