Форум программистов, компьютерный форум CyberForum.ru

Виртуальные абстрактные базовые классы - C++

Восстановить пароль Регистрация
 
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 16:33     Виртуальные абстрактные базовые классы #1
Привет всем!:-) Вчера столкнулся со следующей проблемой: компилятор ругается на чистый виртуальный деструктор. Собственно листинги:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//workermi.h
#ifndef WORKERMI_H_
#define WORKERMI_H_
 
#include <iostream>
#include <string>
 
//abstract base class
class Worker {
private:
    std::string fullname;
    long id;
protected:
    virtual void Data() const;
    virtual void Get();
public:
    Worker() : fullname("no one"), id(0L) { }
    Worker(const std::string & s, long i) : fullname(s), id(i) { }
    //~Worker();
    virtual ~Worker() = 0;
    virtual void Set() = 0;         // cleanly virtual function
    virtual void Show() const = 0;
};
 
class Waiter : virtual public Worker {
private:
    int panache;
protected:
    virtual void Data() const;
    virtual void Get();
public:
    Waiter() : Worker(), panache(0) { }
    Waiter(const std::string & s, long i, int p = 0) :
        Worker(s, i), panache(p) { }
    Waiter(const Worker & wk, int p = 0) :
        Worker(wk), panache(p) { }
    //~Waiter();
    void Set();
    void Show() const;
};
 
class Singer : virtual public Worker {
protected:
    enum { other, alto, contralto, soprano, bass,
            baritone, tenor };
    enum { Vtypes = 7 };
    virtual void Data() const;
    virtual void Get();
private:
    static char *pv [Vtypes];
    int voice;
public:
    Singer() : Worker(), voice(other) { }
    Singer(const std::string & s, long i, int v = other) :
        Worker(s, i), voice(v) { }
    Singer(const Worker & wk, int v = other) :
        Worker(wk), voice(v) { }
    //~Singer();
    void Set();
    void Show() const;
};
 
class SingingWaiter: public Waiter, public Singer {
protected:
    void Data() const;
    void Get();
public:
    SingingWaiter() { }
    SingingWaiter(const std::string & s, long i, int p = 0, int v = other) :
        Worker(s, i), Waiter(s, i, p), Singer(s, i, v) { }
    SingingWaiter(const Worker & wk, long i = 0, int v = other) :
        Worker(wk), Waiter(wk, i), Singer(wk, v) { }
    SingingWaiter(const Waiter & wt, int v = other) :
        Worker(wt), Waiter(wt), Singer(wt, v) { }
    SingingWaiter(const Singer & sg, long i = 0) :
        Worker(sg), Waiter(sg, i), Singer(sg) { }
    //~SingingWaiter();
    void Set();
    void Show() const;
};
 
#endif /* WORKERMI_H_ */
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//workermi.cpp
#include "workermi.h"
 
//============================================= Worker
void Worker::Data() const {
    std::cout << "Name:" << fullname << std::endl;
    std::cout << "ID: " << id << std::endl;
}
 
void Worker::Get() {
    std::getline(std::cin, fullname);
    std::cout << "Enter ID of the worker: ";
    std::cin >> id;
    while(std::cin.get() != '\n')
        continue;
}
 
//============================================= Waiter
void Waiter::Data() const {
    std::cout << "Panache index: " << panache << std::endl;
}
 
void Waiter::Get() {
    std::cout << "Enter the Panache index: ";
    std::cin >> panache;
    while(std::cin.get() != '\n')
        continue;
}
 
void Waiter::Set() {
    std::cout << "Enter first and second name of the Waiter: ";
    Worker::Get();
    Get();
}
 
void Waiter::Show() const {
    std::cout << "The Waiter category\n";
    Worker::Data();
    Data();
}
 
//============================================= Singer
char * Singer::pv [Singer::Vtypes] = { "other", "alto", "contralto",
        "soprano", "bass", "baritone", "tenor"};
 
void Singer::Data() const {
    std::cout << "Vocal range: " << pv[voice] << std::endl;
}
 
void Singer::Get() {
    std::cout << "Enter vocal range value of the singer: " << std::endl;
    int i;
    for(i = 0; i < Vtypes; i++) {
        std::cout << i << ": " << pv[i] << " ";
        if (i % 4 == 3)
            std::cout << std::endl;
    }
    if (i%4 != 0)
        std::cout << '\n';
    std::cin >> voice;
    while(std::cin.get() != '\n')
        continue;
}
 
void Singer::Set() {
    std::cout << "Enter first and second name of the Singer: ";
    Worker::Get();
    Get();
}
 
void Singer::Show() const {
    std::cout << "The Singer category\n";
    Worker::Data();
    Data();
}
 
//============================================= SingingWaiter
 
void SingingWaiter::Data() const {
    Waiter::Data();
    Singer::Data();
}
void SingingWaiter::Get() {
    Waiter::Get();
    Singer::Get();
}
 
void SingingWaiter::Set() {
    std::cout << "Enter first and second name of the Singer: ";
    Worker::Get();
    Get();
}
 
void SingingWaiter::Show() const {
    std::cout << "The SingingWaiter category\n";
    Worker::Data();
    Data();
}
C++
1
2
3
4
5
6
7
8
//QueWorMain.h
#include <iostream>
#include "workermi.h"
 
int main() {
    std::cout << "Hello" << std::endl;
    return 0;
}
Вот что выстреливает консоль...

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Console
Building target: Prta_G14_zL3
Invoking: Cross G++ Linker
g++  -o "Prta_G14_zL3"  ./QueWorMain.o ./bank.o ./queue.o ./workermi.o   
./workermi.o: In function `~Waiter':
/home/farik/Prog/Workspace/Prta_G14_zL3/Debug/../workermi.h:24: undefined reference to `Worker::~Worker()'
/home/farik/Prog/Workspace/Prta_G14_zL3/Debug/../workermi.h:24: undefined reference to `Worker::~Worker()'
./workermi.o: In function `~Singer':
/home/farik/Prog/Workspace/Prta_G14_zL3/Debug/../workermi.h:41: undefined reference to `Worker::~Worker()'
/home/farik/Prog/Workspace/Prta_G14_zL3/Debug/../workermi.h:41: undefined reference to `Worker::~Worker()'
./workermi.o: In function `~SingingWaiter':
/home/farik/Prog/Workspace/Prta_G14_zL3/Debug/../workermi.h:62: undefined reference to `Worker::~Worker()'
./workermi.o:/home/farik/Prog/Workspace/Prta_G14_zL3/Debug/../workermi.h:62: more undefined references to `Worker::~Worker()' follow
collect2: выполнение ld завершилось с кодом возврата 1
make: *** [Prta_G14_zL3] Ошибка 1
Каждый деструктор полюбому обращается к Worker::~Worker(). Поэтому я так понял, что ошибка именно в нем. Изменил определение virtual ~Worker() = 0; на ~Worker();. Тогда работает... Но вить при наследовании деструкторы обязательно должны быть виртуальными!?!?!

Также есть сомнение на счет того, что в классе SingingWaiter должно быть 2 объекта Worker, но используя ВИРТУАЛЬНЫЕ КЛАССЫ мы решаем проблему, в связи с чем, в конструкторе SingingWaiter явно указываем каким образом инициализировать объект Worker... Но вот с деструктором че будет непонятно???
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.03.2013, 16:33     Виртуальные абстрактные базовые классы
Посмотрите здесь:

C++ Виртуальные функции. Абстрактные классы.
C++ Абстрактные базовые классы
C++ Абстрактные классы, виртуальные функции
Абстрактные классы C++
C++ Абстрактные классы
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
07.03.2013, 16:38     Виртуальные абстрактные базовые классы #2
Цитата Сообщение от Lopster92 Посмотреть сообщение
Но вить при наследовании деструкторы обязательно должны быть виртуальными!?!?!
А так?
C++
1
virtual ~Worker();
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 16:41  [ТС]     Виртуальные абстрактные базовые классы #3
Цитата Сообщение от alsav22 Посмотреть сообщение
А так?
C++
1
virtual ~Worker();
Пробовал, те же ошибки выдает...
HighPredator
 Аватар для HighPredator
5347 / 1730 / 320
Регистрация: 10.12.2010
Сообщений: 5,112
Записей в блоге: 3
07.03.2013, 16:52     Виртуальные абстрактные базовые классы #4
Lopster92, все правильно вам компилятор ругается. Если вы хотите, чтобы это работало, то вам придется дать деструктору тело, даже пустое.
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 17:00  [ТС]     Виртуальные абстрактные базовые классы #5
Цитата Сообщение от HighPredator Посмотреть сообщение
Lopster92, все правильно вам компилятор ругается. Если вы хотите, чтобы это работало, то вам придется дать деструктору тело, даже пустое.
Так я тоже пробовал:-)

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Building file: ../workermi.cpp
Invoking: Cross G++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"workermi.d" -MT"workermi.d" -o "workermi.o" "../workermi.cpp"
../workermi.cpp:43:41: предупреждение: deprecated conversion from string constant to «char*» [-Wwrite-strings]
../workermi.cpp:43:41: предупреждение: deprecated conversion from string constant to «char*» [-Wwrite-strings]
../workermi.cpp:43:41: предупреждение: deprecated conversion from string constant to «char*» [-Wwrite-strings]
../workermi.cpp:43:41: предупреждение: deprecated conversion from string constant to «char*» [-Wwrite-strings]
../workermi.cpp:43:41: предупреждение: deprecated conversion from string constant to «char*» [-Wwrite-strings]
../workermi.cpp:43:41: предупреждение: deprecated conversion from string constant to «char*» [-Wwrite-strings]
../workermi.cpp:43:41: предупреждение: deprecated conversion from string constant to «char*» [-Wwrite-strings]
Finished building: ../workermi.cpp
 
Building target: Prta_G14_zL3
Invoking: Cross G++ Linker
g++  -o "Prta_G14_zL3"  ./QueWorMain.o ./bank.o ./queue.o ./workermi.o   
./workermi.o:(.rodata._ZTV13SingingWaiter[vtable for SingingWaiter]+0x28): undefined reference to `SingingWaiter::~SingingWaiter()'
./workermi.o:(.rodata._ZTV13SingingWaiter[vtable for SingingWaiter]+0x30): undefined reference to `SingingWaiter::~SingingWaiter()'
./workermi.o:(.rodata._ZTV13SingingWaiter[vtable for SingingWaiter]+0x70): undefined reference to `non-virtual thunk to SingingWaiter::~SingingWaiter()'
./workermi.o:(.rodata._ZTV13SingingWaiter[vtable for SingingWaiter]+0x78): undefined reference to `non-virtual thunk to SingingWaiter::~SingingWaiter()'
./workermi.o:(.rodata._ZTV13SingingWaiter[vtable for SingingWaiter]+0xd8): undefined reference to `virtual thunk to SingingWaiter::~SingingWaiter()'
./workermi.o:(.rodata._ZTV13SingingWaiter[vtable for SingingWaiter]+0xe0): undefined reference to `virtual thunk to SingingWaiter::~SingingWaiter()'
./workermi.o:(.rodata._ZTC13SingingWaiter0_6Waiter[vtable for SingingWaiter]+0x28): undefined reference to `Waiter::~Waiter()'
./workermi.o:(.rodata._ZTC13SingingWaiter0_6Waiter[vtable for SingingWaiter]+0x30): undefined reference to `Waiter::~Waiter()'
./workermi.o:(.rodata._ZTC13SingingWaiter0_6Waiter[vtable for SingingWaiter]+0x90): undefined reference to `virtual thunk to Waiter::~Waiter()'
./workermi.o:(.rodata._ZTC13SingingWaiter0_6Waiter[vtable for SingingWaiter]+0x98): undefined reference to `virtual thunk to Waiter::~Waiter()'
./workermi.o:(.rodata._ZTC13SingingWaiter16_6Singer[vtable for SingingWaiter]+0x28): undefined reference to `Singer::~Singer()'
./workermi.o:(.rodata._ZTC13SingingWaiter16_6Singer[vtable for SingingWaiter]+0x30): undefined reference to `Singer::~Singer()'
./workermi.o:(.rodata._ZTC13SingingWaiter16_6Singer[vtable for SingingWaiter]+0x90): undefined reference to `virtual thunk to Singer::~Singer()'
./workermi.o:(.rodata._ZTC13SingingWaiter16_6Singer[vtable for SingingWaiter]+0x98): undefined reference to `virtual thunk to Singer::~Singer()'
./workermi.o:(.rodata._ZTV6Singer[vtable for Singer]+0x28): undefined reference to `Singer::~Singer()'
./workermi.o:(.rodata._ZTV6Singer[vtable for Singer]+0x30): undefined reference to `Singer::~Singer()'
./workermi.o:(.rodata._ZTV6Singer[vtable for Singer]+0x90): undefined reference to `virtual thunk to Singer::~Singer()'
./workermi.o:(.rodata._ZTV6Singer[vtable for Singer]+0x98): undefined reference to `virtual thunk to Singer::~Singer()'
./workermi.o:(.rodata._ZTV6Waiter[vtable for Waiter]+0x28): undefined reference to `Waiter::~Waiter()'
./workermi.o:(.rodata._ZTV6Waiter[vtable for Waiter]+0x30): undefined reference to `Waiter::~Waiter()'
./workermi.o:(.rodata._ZTV6Waiter[vtable for Waiter]+0x90): undefined reference to `virtual thunk to Waiter::~Waiter()'
./workermi.o:(.rodata._ZTV6Waiter[vtable for Waiter]+0x98): undefined reference to `virtual thunk to Waiter::~Waiter()'
collect2: выполнение ld завершилось с кодом возврата 1
make: *** [Prta_G14_zL3] Ошибка 1

Или вы имеете в виду дать тело для деструктора Абстрактного Базового Класса?
HighPredator
 Аватар для HighPredator
5347 / 1730 / 320
Регистрация: 10.12.2010
Сообщений: 5,112
Записей в блоге: 3
07.03.2013, 17:07     Виртуальные абстрактные базовые классы #6
Lopster92, тело должно быть у вашего абстрактного деструктора.

Добавлено через 12 секунд
Цитата Сообщение от Lopster92 Посмотреть сообщение
тело для деструктора Абстрактного Базового Класса?
Да.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
07.03.2013, 17:10     Виртуальные абстрактные базовые классы #7
Как ни странно, но код из первого поста у меня компилируется без ошибок.
HighPredator
07.03.2013, 17:15
  #8

Не по теме:

Цитата Сообщение от alsav22 Посмотреть сообщение
Как ни странно, но код из первого поста у меня компилируется без ошибок.
Так там ни один объект не инстанцируется

Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 17:16  [ТС]     Виртуальные абстрактные базовые классы #9
Цитата Сообщение от HighPredator Посмотреть сообщение
Lopster92, тело должно быть у вашего абстрактного деструктора.

Добавлено через 12 секунд

Да.
Спасибо, все работает если дать тело для деструктора АБК. Но с чем это связанно? В книжке Стивена Прата было написано именно:
C++
1
virtual ~Worker() = 0;
Как я понимаю, для АБК экземпляр класса не может быть создан => И деструктор не обязан иметь тело...
HighPredator
 Аватар для HighPredator
5347 / 1730 / 320
Регистрация: 10.12.2010
Сообщений: 5,112
Записей в блоге: 3
07.03.2013, 17:19     Виртуальные абстрактные базовые классы #10
Цитата Сообщение от Lopster92 Посмотреть сообщение
Спасибо, все работает если дать тело для АБК. Но с чем это связанно?
А вы вдумайтесь в суть: деструктор класса наследника (при виртуальном наследовании) должен вызывать деструктор родителя. Как он это сделает, если этого тела де-факто нет? Вызывать-то собственно нечего. Конечно, можно не делать ему тело, но тогда вы не сможете инстанцировать ни одного потомка.
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
07.03.2013, 17:28     Виртуальные абстрактные базовые классы #11

Не по теме:

Цитата Сообщение от HighPredator Посмотреть сообщение
Так там ни один объект не инстанцируется
В студии компилируется. В Code Blocks - ошибки. Особенности студии (или Code Blocks).



Добавлено через 5 минут
Цитата Сообщение от HighPredator Посмотреть сообщение
должен вызывать деструктор родителя
Для кого же его вызывать, если объекта-родителя нет (не может быть создан)?
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 17:29  [ТС]     Виртуальные абстрактные базовые классы #12
Цитата Сообщение от HighPredator Посмотреть сообщение
А вы вдумайтесь в суть: деструктор класса наследника (при виртуальном наследовании) должен вызывать деструктор родителя. Как он это сделает, если этого тела де-факто нет? Вызывать-то собственно нечего. Конечно, можно не делать ему тело, но тогда вы не сможете инстанцировать ни одного потомка.
Ну то, что у него нету тела означает, что я самостоятельно ничего не очищаю... Но вить деструктор, хоть и неявно, все равно выполняет очищение локальных данных класса. Или указав, что деструктор - чистый виртуальный, я не даю выполниться неявному очищению?
HighPredator
 Аватар для HighPredator
5347 / 1730 / 320
Регистрация: 10.12.2010
Сообщений: 5,112
Записей в блоге: 3
07.03.2013, 17:32     Виртуальные абстрактные базовые классы #13
alsav22, ну здрасьте, приехали... В таком примере объекта-родителя и в помине нет (по понятным причинам), однако, смотрите вывод:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
 
using namespace std;
 
class A
{
public:
    virtual ~A()=0;
};
 
A::~A()
{
  cout<<"class A destructor"<<endl;
}
 
class B: public A
{
public:
    virtual ~B();
};
 
B::~B()
{
    cout<<"class B destructor"<<endl;
}
 
void test()
{
    B b;
}
 
 
int main()
{
    test();
    getchar();
    return 0;
}
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 17:38  [ТС]     Виртуальные абстрактные базовые классы #14
Цитата Сообщение от alsav22 Посмотреть сообщение

Для кого же его вызывать, если объекта-родителя нет (не может быть создан)?
Родитель не может быть создан отдельно от потомка... Но внутри потомка он создается:-)
HighPredator
 Аватар для HighPredator
5347 / 1730 / 320
Регистрация: 10.12.2010
Сообщений: 5,112
Записей в блоге: 3
07.03.2013, 17:39     Виртуальные абстрактные базовые классы #15
Lopster92, так гласит стандарт:
12.4.7 A destructor can be declared virtual (10.3) or pure virtual (10.4); if any objects of that class or any derived class are created in the program, the destructor shall be defined.
Это к вопросу о теле.
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 17:59  [ТС]     Виртуальные абстрактные базовые классы #16
Цитата Сообщение от HighPredator Посмотреть сообщение
Lopster92, так гласит стандарт:Это к вопросу о теле.
Благодарю, досконально все объяснили + еще отрывок из стандарта привели!!!
_______________________________________________________
Sincerely,
Lopster92!
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
11.03.2013, 15:54     Виртуальные абстрактные базовые классы
Еще ссылки по теме:

C++ виртуальные базовые классы
C++ Абстрактные классы и чистые виртуальные функции
C++ Абстрактные классы. Виртуальные функции

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

Или воспользуйтесь поиском по форуму:
silent_1991
Эксперт C++
4938 / 3014 / 149
Регистрация: 11.11.2009
Сообщений: 7,024
Завершенные тесты: 1
11.03.2013, 15:54     Виртуальные абстрактные базовые классы #17
Вообще, чистый виртуальный деструктор нужен только для того, чтобы указать, что класс, его содержащий, является абстрактным, в том случае, если все его методы по смыслу должны иметь тело. Т.е. это такой способ сказать компилятору: "да-да, все методы класса реализованы, но я всё равно хочу, чтобы этот класс являлся абстрактным и объектов его нельзя было создать". Для этого в Java и C# перед ключевым словом class пишут abstract. Если не ошибаюсь, в новом стандарте тоже есть нечто подобное, но проверять лень. Если в классе есть хотя бы один чистый виртуальный метод, делать деструктор чистым виртуальным нет смысла. Несмотря на всё это, любой класс обязан иметь деструктор, путь даже тело его остаётся пустым.
Yandex
Объявления
11.03.2013, 15:54     Виртуальные абстрактные базовые классы
Ответ Создать тему
Опции темы

Текущее время: 17:21. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru