Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 4.96/23: Рейтинг темы: голосов - 23, средняя оценка - 4.96
70 / 70 / 7
Регистрация: 04.08.2010
Сообщений: 427
1

Не вызывается конструктор базового класса

04.08.2010, 17:35. Просмотров 4739. Ответов 44
Метки нет (Все метки)

Доброго времени суток.
У меня проблема:в производном классе не вызывается конструктор базового класса.
Думаю описывать класс не стоит, т.к. он простейший.

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
#include<iostream>
#include<cstring>
using namespace std;
class String
{
protected:
    enum {SZ=80};
    char str[SZ];
public:
    String()
    {
        str[0]='\0';
    }
    String(char s[])
    {
        strcpy(str,s);
    }
    void display()const
    {
        cout << str << endl;
    }
};
class Pstring:public String
{
public:
    Pstring(char s[]);
};
Pstring::Pstring(char s[])
{
    if(strlen(s)>SZ-1)
    {
        for(int j=0;j<SZ;j++)
        str[j]=s[j];
        str[SZ-1]='\0';
    }
    else
        String(s);  //Вызов конструктора с параметром не проиходит. 
                                     //Результат пустая строка
};
int main()
{
    Pstring g="Qwertythdththdhdhtdh";
    g.display();
    return 0;
}
Поделитесь мыслью, что не так.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.08.2010, 17:35
Ответы с готовыми решениями:

Не вызывается нужный конструктор базового класса
Здравствуйте. Я пока в процессе изучения С++. Имеется следующая структура классов: Базовый:...

При создании класса конструктор вызывается 2 раза, затем вызывается деструктор о_О
Вот такой кодclass A { public: A(){} virtual ~A(){} }; class C { public:

Вызвать конструктор производного класса без конструктора базового класса
Здравствуйте! У меня есть базовый класс треугольник и производный класс равносторонний...

Наследование: почему вызывается метод базового класса, а не производного?
Всем привет, такой вопрос, почему вызывается в данном коде метод базового класса, а не производного...

44
70 / 70 / 7
Регистрация: 04.08.2010
Сообщений: 427
04.08.2010, 18:32  [ТС] 21
CyBOSSeR, Спасибо, я понял, что только список инициализации вызовет конструктор.
Тему можно закрывать
0
Эксперт С++
2328 / 1701 / 148
Регистрация: 06.03.2009
Сообщений: 3,675
04.08.2010, 18:32 22
fasked, точно. Поторопился.
0
70 / 70 / 7
Регистрация: 04.08.2010
Сообщений: 427
04.08.2010, 18:35  [ТС] 23
C++
1
2
3
4
if(strlen(s)>SZ-1)
strncpy(str,s,SZ-1);
else
strcpy(str,s);
Вот так оптимально
0
158 / 157 / 47
Регистрация: 29.04.2009
Сообщений: 637
04.08.2010, 18:40 24
C
1
String(s).display();
Попробуйте такой вариант для оптимальности.
0
70 / 70 / 7
Регистрация: 04.08.2010
Сообщений: 427
04.08.2010, 18:45  [ТС] 25
Цитата Сообщение от Sekt Посмотреть сообщение
C
1
String(s).display();
Попробуйте такой вариант для оптимальности.
При таком вызове, мой обьект в main, после инициализации будет иметь пустое значение.
0
158 / 157 / 47
Регистрация: 29.04.2009
Сообщений: 637
04.08.2010, 18:50 26
Если в вашем коде сменить строку String(s) на
String(s).display();
Будет пустое значение?
Значет у нас совсем разные компиляторы.
0
70 / 70 / 7
Регистрация: 04.08.2010
Сообщений: 427
04.08.2010, 18:58  [ТС] 27
Цитата Сообщение от Sekt Посмотреть сообщение
Если в вашем коде сменить строку String(s) на
String(s).display();
Будет пустое значение?
Значет у нас совсем разные компиляторы.
Если заменить так, как Вы написали, то значение выведется в консоль, но сам обьект не будет содержать значение.
ЗЫ Компилятор MVS2010
0
158 / 157 / 47
Регистрация: 29.04.2009
Сообщений: 637
04.08.2010, 19:01 28
Цитата Сообщение от LineStown Посмотреть сообщение
но сам обьект не будет содержать значение
Да т.к в String(s).display(); создается конструктор по-умолчанию.Что было обговорено здесь раннее.
0
70 / 70 / 7
Регистрация: 04.08.2010
Сообщений: 427
05.08.2010, 09:51  [ТС] 29
Цитата Сообщение от Sekt Посмотреть сообщение
Да т.к в String(s).display(); создается конструктор по-умолчанию.Что было обговорено здесь раннее.
Но если обьект не получил значение, но каким образом отработал конструктор?
0
0 / 0 / 0
Регистрация: 20.12.2011
Сообщений: 5
12.07.2012, 23:45 30
Возмущает другое: если закаментить кусок кода:
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
#include <iostream>
#include <string.h>
 
using namespace std;
 
class String
{
    protected:
        enum {SZ = 80};
        char str[SZ];
    public:
        String()
        {
            str[0] = '\x0';
        }
        String(char s[])
        {
            strcpy(str, s);
        }
        void display() const
        {
            cout << str;
        }
        operator char*()
        {
            return str;
        }
};
 
class Pstring: public String
{
    public:
        Pstring(char s[])
        {
            if (strlen(s) >= SZ)
            {
                for (int i = 0; i < SZ - 1; i++)
                {
                    str[i] = s[i];
                }
                str[SZ - 1] = '\x0';
            }
            else
            {
                String(s);
            }
        }
};
 
int main ()
{
    Pstring s1 = "0123456789";
    s1.display();
    return 0;
}
то ругается
main.cpp||In constructor ‘Pstring::Pstring(char*)’:|
main.cpp|34|error: no matching function for call to ‘String::String()’|
main.cpp|16|note: candidates are: String::String(char*)|
main.cpp|7|note: String::String(const String&)|
main.cpp|45|error: no matching function for call to ‘String::String()’|
main.cpp|16|note: candidates are: String::String(char*)|
main.cpp|7|note: String::String(const String&)|
main.cpp||In function ‘int main()’:|
main.cpp|52|warning: deprecated conversion from string constant to ‘char*’|
||=== Build finished: 2 errors, 1 warnings ===|


и ещё: раз конструктор базового класса вызывается только в строке инициализации то почему бы не создать фиктивный конструктор производного класса, у которого в строке инициализации был бы нужный конструктор базового? см. ниже строки 33, 34 и 47
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
#include <iostream>
#include <string.h>
 
using namespace std;
 
class String
{
    protected:
        enum {SZ = 80};
        char str[SZ];
    public:
        String()
        {
            str[0] = '\x0';
        }
        String(char s[])
        {
            strcpy(str, s);
        }
        void display() const
        {
            cout << str;
        }
        operator char*()
        {
            return str;
        }
};
 
class Pstring: public String
{
    public:
        Pstring(char s[], bool b): String (s)
        {   }
        Pstring(char s[])
        {
            if (strlen(s) >= SZ)
            {
                for (int i = 0; i < SZ - 1; i++)
                {
                    str[i] = s[i];
                }
                str[SZ - 1] = '\x0';
            }
            else
            {
                Pstring(s, 1);
            }
        }
};
 
int main ()
{
    Pstring s1 = "0123456789";
    s1.display();
    return 0;
}
Но что бы вы думали? Толку нет, хотя s и передаётся в нужный базовый конструктор. Хелп!!!

И ещё вопрос: получается, Лафоре в своей книге привёл заведомо неправильный ответ?

З.Ы. Сей пример и призван проиллюстрировать то, что код используется дважды. Фишка как раз в том, чтобы запустить нужный конструктор базового класса, а не плодить повторы в коде (хоть конкретно в этом примере их и мало), что однако не получается.

Заранее спасибо.

Добавлено через 21 минуту
если закаментить кусок кода (в коде выше забыл закаментить):
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
#include <iostream>
#include <string.h>
 
using namespace std;
 
class String
{
    protected:
        enum {SZ = 80};
        char str[SZ];
    public:
       /* String()
        {
            str[0] = '\x0';
        }*/
        String(char s[])
        {
            strcpy(str, s);
        }
        void display() const
        {
            cout << str;
        }
        operator char*()
        {
            return str;
        }
};
 
class Pstring: public String
{
    public:
        Pstring(char s[])
        {
            if (strlen(s) >= SZ)
            {
                for (int i = 0; i < SZ - 1; i++)
                {
                    str[i] = s[i];
                }
                str[SZ - 1] = '\x0';
            }
            else
            {
                String(s);
            }
        }
};
 
int main ()
{
    Pstring s1 = "0123456789";
    s1.display();
    return 0;
}
0
бжни
2467 / 1676 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
12.07.2012, 23:53 31
Цитата Сообщение от LineStown Посмотреть сообщение
String(s);
вы например тут создаете временный объект, а не вызываете конструктор базового класса
это вам не джава

прочтите, что вам написал CyBOSSeR

Добавлено через 44 секунды
пардон, я слоупок))
0
0 / 0 / 0
Регистрация: 20.12.2011
Сообщений: 5
13.07.2012, 00:35 32
ну а конструктор производного класса можно вызвать из другого конструктора (того же класса)?
0
бжни
2467 / 1676 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
13.07.2012, 00:49 33
VerDicT, нет!
в некоторых случаях это было бы удобно, но в с++ есть заданный стандартом порядок вызовов конструкторов предков и полей
в чем смысл противоречия:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A {
public:
  A() { /* ... */ }
protected:
  int a;
};
 
class B {
public:
  B() {
    a = 100500; // Если бы конструктор можно было бы вызывать из произвольного места
    A();            // то мы могли бы иметь доступ к полям предка до его инициализации
  }
};
Поэтому и есть список инициализации с ограничениями на порядок

к слову в жабе можно по ходу дела вызывать конструктор предка (и не вызывать), но там от этого анархия (я считаю из своего не очень большого опыта писания на жабе)
0
5473 / 4868 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
13.07.2012, 05:38 34
Почитал, посмотрел что компилятор пишет и выскажу своё мнение. Мне кажется, что вот это:
C++
1
String(s);
и вот это:
C++
1
String s;
есть одно и тоже (скобки здесь не играют никакой роли): создание локольного объекта класса String конструктором по умолчанию.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
Pstring::Pstring(char *s)
{
    if(strlen(s) > SZ - 1)
    {
        for(int j = 0; j < SZ; j++)
        str[j] = s[j];
        str[SZ-1] = '\0';
    }
    else
    {
       String (s); // создание локального объекта s конструктором по умолчанию.
    } 
}
При этом в str записывается пустая строка.
И когда ТС пишет, в конструкторе производного класса:
C++
1
 String (s);
, то это всё равно, что написать
C++
1
String s;
Поэтому s в String (s); не имеет никакого отношения к s, в парметрах конструктора Pstring. Для ясности можно так написать:
C++
1
2
String(s);
s.display();
Невозможно в теле конструктора производного класса создать объект базового класса, который будет являтся частью объекта производного класса. Создаётся временный объект, который перестаёт существовать после выхода из конструктора производного класса. Возможно только ДО вхождения в тело конструктора (через список инициализаторов). Поэтому, в данном примере создаётся, конструктором по умолчанию, просто временный объект s базового класса, который не является частью никакого объекта производного класса. А через g.display(); выводится поле str объекта базового класса, который создан, конструктором по умолчанию, при создании объекта g производного класса и является его частью. Если так написано:
C++
1
String(s).display();
, то будет создан временный, неименованный объект базового класса (уже не конструктором по умолчанию), поле str которого будет проинициализированно значением параметра s и выведено на консоль, после чего этот объект станет недоступен (исчезнет).

Добавлено через 8 минут
Цитата Сообщение от LineStown Посмотреть сообщение
CyBOSSeR, Спасибо, я понял, что только список инициализации вызовет конструктор.
Тему можно закрывать
Не только. Если нужно явно, то через список. Если в списке не задан, то будет вызываться неявно конструктор по умолчанию при создании каждого объекта производного класса.

Добавлено через 39 минут
Цитата Сообщение от alex_x_x Посмотреть сообщение
B() {
a = 100500; // Если бы конструктор можно было бы вызывать из произвольного места
A(); // то мы могли бы иметь доступ к полям предка до его инициализации
Можно вызывать из произвольного места, но созданный объкет-предок, не будет иметь никакого отношения к тому объекту-наследнику из которого был вызван конструктор. А наследники имеют доступ к полям только тех предков, которые являются их частью.
0
193 / 173 / 30
Регистрация: 10.07.2012
Сообщений: 799
13.07.2012, 06:56 35
Цитата Сообщение от LineStown Посмотреть сообщение
enum {SZ=80};
не первый раз такой код вижу... объясните, будьте любезны, в чем смысл писать такую...забавную штуковину...
0
бжни
2467 / 1676 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
13.07.2012, 07:47 36
Цитата Сообщение от alsav22 Посмотреть сообщение
Можно вызывать из произвольного места, но созданный объкет-предок, не будет иметь никакого отношения к тому объекту-наследнику из которого был вызван конструктор. А наследники имеют доступ к полям только тех предков, которые являются их частью.
с цпп даже нет такого синтаксиса - это была фантазия
0
5473 / 4868 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
13.07.2012, 12:10 37
Цитата Сообщение от alex_x_x Посмотреть сообщение
с цпп даже нет такого синтаксиса - это была фантазия
Я не о синтаксисе. Код случайно в цитату попал. Я о сути: можно или нельзя вызвать из произвольного места и, если мжно, то что мы имеем.

Добавлено через 32 минуты
Сообщение от LineStown
enum {SZ=80};
не первый раз такой код вижу... объясните, будьте любезны, в чем смысл писать такую...забавную штуковину...
Один из способов объявления констант в классе. Дело в том, что сделать в объявлении класса так:
C++
1
2
3
4
5
6
7
class String
{
    protected:
        const int SZ = 80;
        char str[SZ];
    public:
....................
не получится, потому что тогда, под переменную SZ, должна быть выделена память, а память под переменные класса выделяется при создании объекта класса, а не при объявлении класса. Если же задано перечисление
C++
1
enum {SZ=80};
, то это всего лишь символическое имя , которое компилятор использует в пределах этого класса и заменяет на 80. Ещё одни способ объявления констант в классах:
C++
1
static const int SZ = 80;
. В этом случае, как и для всех других статических переменных класса, память под SZ в объектах класса тоже не выделяется.
0
бжни
2467 / 1676 / 135
Регистрация: 14.05.2009
Сообщений: 7,162
13.07.2012, 12:23 38
Цитата Сообщение от alsav22 Посмотреть сообщение
не получится, потому что тогда, под переменную SZ, должна быть выделена память, а память под переменные класса выделяется при создании объекта класса, а не при объявлении класса. Если же задано перечисление
константа по сути может не принадлежать объекту физически, так же как и статические методы не принадлежат объектам
здесь нет никакой магии, просто язык кривой
0
5473 / 4868 / 831
Регистрация: 04.06.2011
Сообщений: 13,587
13.07.2012, 13:13 39
Цитата Сообщение от alex_x_x Посмотреть сообщение
константа по сути может не принадлежать объекту физически,
Да. Просто не принадлежит, поэтому так и объявляется. Храниться отдельно от объектов. Доступна для всех объектов этого класса, так же как и методы класса.
0
0 / 0 / 0
Регистрация: 20.12.2011
Сообщений: 5
13.07.2012, 22:48 40
Я напомню, что главной идеей этого упражнения было многократное использование кода вместо перепечатывания.
Я решил этот вопрос так (строки 11-14, 22, 49):
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
#include <iostream>
#include <string.h>
 
using namespace std;
 
class String
{
    protected:
        enum {SZ = 80};
        char str[SZ];
        void constructor(char s[])
        {
            strcpy(str, s);
        }
    public:
        String()
        {
            str[0] = '\x0';
        }
        String(char s[])
        {
            constructor(s);
        }
        void display() const
        {
            cout << str;
        }
        operator char*()
        {
            return str;
        }
};
 
class Pstring: public String
{
    public:
        Pstring(char s[])
        {
            if (strlen(s) >= SZ)
            {
                for (int i = 0; i < SZ - 1; i++)
                {
                    str[i] = s[i];
                }
                str[SZ - 1] = '\x0';
            }
            else
            {
                String::constructor(s);
            }
        }
};
 
int main ()
{
    Pstring s1 = "0123456789";
    s1.display();
    return 0;
}
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
13.07.2012, 22:48

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Конструктор базового класса
Такая проблема: имеется конструктор базового класса ErrorDataErrorData(ErrorCod cod, bool...

Конструктор базового класса
Привет, друзья, есть, к примеру, такие классы: class Base { public: int x; Base() { }...

Будет ли утрачена память, когда конструктор копирования вызывается для уже существующего объекта класса?
class A { char * v; A(); ~A(); A(const A &amp;obj); } ///////////////////// A::A() {

this(Всегда ли вызывается конструктор при не явной передачи объекта в конструктор)
class Test { int i; public: void test(int i) { this -&gt; i = i; } }; Конструктор...


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

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

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