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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
#1

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

07.03.2013, 16:33. Просмотров 826. Ответов 16
Метки нет (Все метки)

Привет всем!:-) Вчера столкнулся со следующей проблемой: компилятор ругается на чистый виртуальный деструктор. Собственно листинги:

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... Но вот с деструктором че будет непонятно???
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.03.2013, 16:33
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Виртуальные абстрактные базовые классы (C++):

Абстрактные базовые классы - C++
Помогите решить пожалуйста!) Задание 1 . Создать базовый класс - фигура, и производные класс - круг, прямоугольник, трапеция....

Абстрактные базовые классы - C++
Не могу создать экземпляр производного от АБК класса: #pragma once class BaseEllips { private: double x; double y; public: ...

Виртуальные базовые классы - C++
Необходимо написать примеры с комментариями использования виртуальных базовых классов

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

Виртуальные функции. Абстрактные классы. - C++
Есть у меня абстрактный класс class DataManager { protected: Configuration configuration; public:...

Абстрактные классы. Виртуальные функции - C++
Помогите, пожалуйста. Класс : место - область - город - мегаполис 1. Определить иерархию системы, которая заключается в...

16
alsav22
5425 / 4820 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
07.03.2013, 16:38 #2
Цитата Сообщение от Lopster92 Посмотреть сообщение
Но вить при наследовании деструкторы обязательно должны быть виртуальными!?!?!
А так?
C++
1
virtual ~Worker();
0
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 16:41  [ТС] #3
Цитата Сообщение от alsav22 Посмотреть сообщение
А так?
C++
1
virtual ~Worker();
Пробовал, те же ошибки выдает...
0
HighPredator
5541 / 1854 / 346
Регистрация: 10.12.2010
Сообщений: 5,472
Записей в блоге: 2
07.03.2013, 16:52 #4
Lopster92, все правильно вам компилятор ругается. Если вы хотите, чтобы это работало, то вам придется дать деструктору тело, даже пустое.
0
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

Или вы имеете в виду дать тело для деструктора Абстрактного Базового Класса?
0
HighPredator
5541 / 1854 / 346
Регистрация: 10.12.2010
Сообщений: 5,472
Записей в блоге: 2
07.03.2013, 17:07 #6
Lopster92, тело должно быть у вашего абстрактного деструктора.

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

Не по теме:

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

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

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

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

Не по теме:

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



Добавлено через 5 минут
Цитата Сообщение от HighPredator Посмотреть сообщение
должен вызывать деструктор родителя
Для кого же его вызывать, если объекта-родителя нет (не может быть создан)?
0
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 17:29  [ТС] #12
Цитата Сообщение от HighPredator Посмотреть сообщение
А вы вдумайтесь в суть: деструктор класса наследника (при виртуальном наследовании) должен вызывать деструктор родителя. Как он это сделает, если этого тела де-факто нет? Вызывать-то собственно нечего. Конечно, можно не делать ему тело, но тогда вы не сможете инстанцировать ни одного потомка.
Ну то, что у него нету тела означает, что я самостоятельно ничего не очищаю... Но вить деструктор, хоть и неявно, все равно выполняет очищение локальных данных класса. Или указав, что деструктор - чистый виртуальный, я не даю выполниться неявному очищению?
0
HighPredator
5541 / 1854 / 346
Регистрация: 10.12.2010
Сообщений: 5,472
Записей в блоге: 2
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;
}
1
Lopster92
3 / 3 / 0
Регистрация: 25.12.2009
Сообщений: 49
07.03.2013, 17:38  [ТС] #14
Цитата Сообщение от alsav22 Посмотреть сообщение

Для кого же его вызывать, если объекта-родителя нет (не может быть создан)?
Родитель не может быть создан отдельно от потомка... Но внутри потомка он создается:-)
1
HighPredator
5541 / 1854 / 346
Регистрация: 10.12.2010
Сообщений: 5,472
Записей в блоге: 2
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.
Это к вопросу о теле.
2
07.03.2013, 17:39
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
07.03.2013, 17:39
Привет! Вот еще темы с ответами:

Виртуальные базовые классы/закрытое наследование - C++
Хотел уточнить правильно ли я понял материал. Если я породил два класса через виртуальное, открытое наследование от одного базового класса,...

Абстрактные классы и чистые виртуальные функции - C++
У Р. Лафоре написано: И вот, есть такой пример из его книги: #include &lt;iostream&gt; #include &quot;msoftcon.h&quot; using namespace std; ...

Абстрактные классы. Виртуальные функции. Задача - C++
ПОМОГИТЕ ПОЖАЛУЙСТА РЕШИТЬ ЗАДАЧУ: #include&lt;stdio.h&gt; #include&lt;conio.h&gt; #include&lt;locale.h&gt; #include&lt;time.h&gt; #include&lt;stdlib.h&gt; ...

Наследование: Чистые Виртуальные функции и Абстрактные классы - C++
Добрый вечер помогите пожалуйста вывести на экран то что мы вводим с клавиатуры ( int s , char d ) #include &quot;stdafx.h&quot; ...


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

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru