Показать полную графическую версию : Порядок построения классов
Где можно почитать про порядок построения классов (с виртуальными функциями)? Пример:
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() или какая-нить ошибка, что класс недостроен?
virtual void foo() {cout << "A::foo()\n";} »
может я чтото уже подзабыл из классов си++ но член класса объявленый виртуальным не может иметь реализацию тут же.
и объявление класса должно быть начинатся с class <name> . Почитать можно в любой более менее нормальной книге по Си++ . Ну а про классы в своей библиотеке нашел "Павловская Т. C++ Объектно-ориентировочное программирование. Практикум"
не может иметь реализацию тут же »
Почему нет? классический пример из книги страуструпа:
class shape_t
{
public:
virtual ~shape_t() {}
}
Методы, реализованные в описании раскрываются inline когда могут (если не могут, то не inline)
должно быть начинатся с class <name> »
struct - это тоже класс (любой тип данных есть класс для C++)Павловская Т. C++ Объектно-ориентировочное программирование. Практикум »
Есть ссылка на "скачать в интернете"?
struct »
не есть истинный класс - в нем нет такой фишки как private.
Где скачать не знаю, я двд с книгами заказал - куча чего полезного и интересного.
фишки как private. »
не верю:
struct A
{
private:
int _priv_data;
};
вполне собирается любым компилятором C++. Ссылку на книжку не пока могу дать
Более того, даже int есть класс, а у него даже и методов то нет...
да, извини, согласен - давно классами в сях не баловался. А верхний пример будет откомпилирован и выведет 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();
}
#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.
Только хоть используй 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 раза. Каждый раз результаты разные.
a->foo();
b->foo(); »
Испльзования класса хранилища (auto или в свободной памяти) не влияет на правила полиморфизма и построения классов, поэтому через operator new() и указатели не было смысла переделывать
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)
~либо~
Верно ли что использовать недостроенные классы категорически нельзя, реализация поведения остаётся на усмотрение компилятора.
Я ни того, ни другого утверждения ещё не встречал
в случае использования недостроенного класса »
наверно ты имеешь ввиду абстрактный класс.
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().
Я не утверждаю что это истина и верно на всех компиляторах хотя логически должно.
наверно ты имеешь ввиду абстрактный класс. »
Я имел ввиду именно НЕДОСТРОЕННЫЙ класс С РЕЛИЗАЦИЕЙ (когда непонятно, как должна себя вести софтина)
Тогда я чтото не пойму :
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";}
}
По каким критериям он не достроен и одновременно с реализацией. По-моему вполне достроен и реализован.
В конструктор C передаётся часть недостроенного класса B с собственной реализацией виртуальных функций (*this)
В конструкторе передается не сам не достроенный объект а его указатель типа B. В самое классе C он преобразуется в класс A (он же подкласс его) что дает a.foo() корректно. Вот вопрос что будет если сделать так C(B& b) {b.foo();} - надо будет дома проверить :)
если сделать так C(B& b) {b.foo();} »
С этим как раз понятно, в лучшем случае слетит ибо используем неинициализированную память с мусором.
(он же подкласс его) что дает 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()
Это особенность компилятора или стандарт с++ такой?
© OSzone.net 2001-2012
vBulletin v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.