LINUX.ORG.RU

[C++] Множественное наследование

 


0

0

Есть класс A, у которого есть метод get(const char *). Необходимо написать потомка класса A и QObject. пишу так:

class A
{
public:
A();
~A();
int get(const char *);
}

class B : public QObject, public A
{
Q_OBJECT
public:
B();
~B();
int get(bool);
}

Далее делаю так:

B *var = new B();
int i = var->get("text");

И при компиляции получаю сообщение о том, что класс B не имеет такого метода. Приходится явно указывать из какого базового класса я хочу получить метод:

int i = var->A::get("text");

Этого можно как-то избежать?


> И при компиляции получаю сообщение о том, что класс B не имеет такого метода.

ты сначала расскажи как у тебя без ; в конце описания классов компилится, после добавления у меня все компилится нормально

lester ★★★★
()

class A
{
public:
A() {}
int get(const char *) { return 0; }
};

class B : public A
{
public:
B() {}
~B() {}
int get(bool) { return 1; }
};

int main( void )
{
B *var = new B();
int i = var->get("text");

return 0;
}

lester ★★★★
()
Ответ на: комментарий от lester

Здесь пример, взятый из головы, но отражающий общую картину. В реальном проекте все ; расставлены а тут я проглядел.

Torvus
() автор топика
Ответ на: комментарий от lester

Нет, без явного указания базового класса не собирается. Говорит, что нет такого метода.

Компилятор g++. Версию не не помню, но довольно-таки старый. Могу завтра на работе посмотреть.

Torvus
() автор топика
Ответ на: комментарий от smh

> А как ошибка выглядит?

Дословно не скажу но означала, что не найден метод и в качестве кандидата предлагается только метод из класса B

Torvus
() автор топика
Ответ на: комментарий от lester

> может вместо "public A" написано просто "А"?

Тогда бы компилятор ругался на то, что этот метод protected, но найден. Однозначно нет. Проверял несколько раз.

Torvus
() автор топика

У меня не ругается ("text" неявно приводится к bool видимо), но вообще-то ошибка есть. В наследованном классе нельзя просто перегрузить метод базового класса, в новом нужно описать и get(char*), и get(bool).

staseg ★★★★★
()
Ответ на: комментарий от staseg

Ну и да, множественно наследование здесь совершенно ни при чем.

staseg ★★★★★
()
Ответ на: комментарий от staseg

>"text" неявно приводится к bool

да. одно из волшебных свойств C++

jtootf ★★★★★
()

Ну, если из списка базовых классов исключить QObject, то все работает на ура.

Torvus
() автор топика

Кстати, если это важно, то используется Qt-3.3.3

Torvus
() автор топика
Ответ на: комментарий от staseg

>приведенный пример не отражает того безумия, что творится в реальном коде

*голос с галёрки* подробности! подробности давай!

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

>*голос с галёрки* подробности! подробности давай!

*ответ с трибуны* об этом нужно топикстартера спросить. мне уж самому стало интересно, в чем там дело)

staseg ★★★★★
()
Ответ на: комментарий от Torvus

> Нет, без явного указания базового класса не собирается. Говорит, что нет такого метода.

Эх, когда долго не пользуешься С++, все забываешь (это я про себя:-). Если в С++ в производном классе метод имеет такое же имя, как и методы в базовом, то он перекрывает все методы из базового класса. Добавь using A::get в класс В:

class B : public QObject, public A
{
Q_OBJECT
public:
B();
~B();
using A::get;
int get(bool);
};

smh ★★★
()

Пишу:

class A
{
  public:
    A() {}
    virtual ~A() {}
    int get(const char*){return 0;}
};

class B : public QObject, public A
{
  Q_OBJECT
  public:
    B():QObject(),A() {}
    ~B() {}
    int get(bool) {return 1;}
};

int main(int, char**)
{
  B *var = new B();
  qWarning( "%d", var->get("text") );
  return 0;
}

При компиляции получаю:

g++ -o ../bin/trouble trouble.o -L/usr/lib/qt-3.3.3/lib -L/usr/X11R6/lib -lqt-mt -lXext -lX11 -lm -lpthread
trouble.o(.text+0x21): In function `basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::data(void) const':
/usr/lib/gcc-lib/i486-linux/2.95.4/../../../../include/g++-3/std/bastring.h:152: undefined reference to `B::B(void)'
trouble.o(.text+0x61):/usr/lib/gcc-lib/i486-linux/2.95.4/../../../../include/g++-3/std/bastring.h:152: undefined reference to `B::get(bool)'
collect2: ld returned 1 exit status

Компилятор:

torvus[ ~ ] > g++ --version
2.95.4

Torvus
() автор топика
Ответ на: комментарий от smh

> Добавь using A::get в класс В

После добавления вылезло:

trouble.cpp:39: cannot adjust access to `int A::get(const char *)' in `class B'

trouble.cpp:38: because of local method `int B::get(bool)' with same name

Torvus
() автор топика

А вот с чего все началось:

class Data
{
public:
  Data( Connection *connection = 0 );
  virtual ~Data();
/* тут много разных методов */
  bool setAt    ( int pos );
  bool setAt    ( const char *value, const char *column );
  bool setAt    ( const char *value, int column );
};

class DataExt : public QObject, public Data
{
Q_OBJECT
  DataExt( Connection *connection = 0 );
  ~DataExt();
  bool setAt ( const QMap< QString, QRegExp > &conditions );
};

int main ( int argc, char *argv[] )
{
  QApplication app( argc, argv );
  Connection *connection = new Connection();

  DataExt *data = new DataExt( connection );
  data->setAt( QMap< QString, QRegExp >() ); /* работает */
  data->setAt( "23456", "id" );              /* не работает */
  return 0;
}

Как я уже сказал, добавление using Data::setAt; не помогло.

Torvus
() автор топика
Ответ на: комментарий от Torvus

>Q_OBJECT

>public:

> DataExt( Connection *connection = 0 );

fixed

Torvus
() автор топика

В классе B перегрузить get?

class A
{
public:
A();
~A();
int get(const char *);
};

class B : public QObject, public A
{
Q_OBJECT
public:
B();
~B();
int get(const char *a){return A::get(a);};
int get(bool);
};

B *var = new B();
int i = var->get("text");

josephson ★★
()
Ответ на: комментарий от josephson

> В классе B перегрузить get?

Думал об этом, но не хочется писать много лишнего кода (ленивый я).

Torvus
() автор топика
Ответ на: комментарий от Torvus

$ cat test6.cxx 
#include <iostream>

class A
{
    public:
        A() {}
        int get(const char *) { return 0; }
};
 
class B : public A
{
    public:
        B() {}
        ~B() {}
        using A::get;
        int get(bool b) { return 1; }
};
 
int main( void )
{
    B *var = new B();
    int i = var->get("text");
    std::cout << i << '\n' ;
    return 0;
}
$ g++ -Wall test6.cxx && ./a.out 
0
$ g++ --version
g++ (GCC) 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> Хотя вопрос о переходе на qt4 явно надо ставить.

Это вопрос к заказчику, а не ко мне.

Torvus
() автор топика
Ответ на: комментарий от www_linux_org_ru

> class B : public A

Я, кажется говорил, что не компилируется только при множественном наследовании, и если убрать QObject из списка базовых классов, то все работает даже без добавления using A::get

Torvus
() автор топика
Ответ на: комментарий от Torvus

> Я, кажется говорил, что не компилируется только при множественном наследовании, и если убрать QObject из списка базовых классов, то все работает даже без добавления using A::get

Определись с компилятором. Для 2.95 лично я не собираюсь даже думать о твоих проблемах, как другие -- это их дело.

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от Torvus

>и если убрать QObject из списка базовых классов, то все работает даже без добавления using A::get

оно не может работать, поскольку тогда это значило бы, что gcc не соответствует стандарту. :-) скорее всего у тебя происходят неявные приведения типов и все методы вызываются из производного, а не базового класса (как уже заметили, когда строка в bool привелась).

smh ★★★
()
Ответ на: комментарий от smh

> оно не может работать, поскольку тогда это значило бы, что gcc не соответствует стандарту.

*его* gcc действительно не соответсвует стандарту, т.к. это 2.95

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от www_linux_org_ru

> g++ --version > 2.95.4

Стоит обновить компилятор.

smh ★★★
()
Ответ на: комментарий от Torvus

>Думал об этом, но не хочется писать много лишнего кода (ленивый я).

Не вымахивайся. Либо старый компилятор либо потакание лени, но не всё сразу.

legolegs ★★★★★
()
Ответ на: комментарий от Torvus

А если для примера от Torvus:

int main(int, char**)
{
B *var = new B();
qWarning( "%d", var->get("text") );
return 0;
}

сделать так:

int main(int, char**)
{
A *var = new B(); // смотреть тут
qWarning( "%d", var->get("text") );
return 0;
}

andreyu ★★★★★
()
Ответ на: комментарий от smh

> оно не может работать, поскольку тогда это значило бы, что gcc не соответствует стандарту

Да что вы говорите! По-моему, базовый принцип наследования говорит о том, что потомок содержит все нестатичные члены и методы базового класса без явного указания на это (т.е. без всяких using)

Torvus
() автор топика
Ответ на: комментарий от andreyu

> A *var = new B();

Тогда для доступа к методам класса B придется использовать уродливое ((B*)var)->...

Torvus
() автор топика
Ответ на: комментарий от smh

Кстати, насколько я помню, то using необходимо добавлять только при конфликте имен членов базовых классов, т.е. если метод get есть и в классе A и в классе QObject, то необходимо явно указать какой из этих двух методов необходимо использовать

Torvus
() автор топика
Ответ на: комментарий от Torvus

> Да что вы говорите! По-моему, базовый принцип наследования говорит о том, что потомок содержит все нестатичные члены и методы базового класса без явного указания на это (т.е. без всяких using)

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

Я, чтоб не быть голословным, даже не поленился и в гугле поискал. Первой ссылкой Страуструп: http://www.research.att.com/~bs/bs_faq2.html#overloadderived

smh ★★★
()
Ответ на: комментарий от smh

> Если он так не работает - твой компилятор сам-знаешь-что

Вместо того что бы обсуждать кривизну моего компилятора (его выбор не моя прихоть, а требование заказчика), лучшеб предложили решение проблемы.

Torvus
() автор топика
Ответ на: комментарий от Torvus

> Вместо того что бы обсуждать кривизну моего компилятора (его выбор не моя прихоть, а требование заказчика), лучшеб предложили решение проблемы.

Тебе уже кучу решений предложили.

smh ★★★
()
Ответ на: комментарий от smh

> Тебе уже кучу решений предложили.

И кроме явного переописания перегружаемых методов базового класса ниодин не работает

Torvus
() автор топика
Ответ на: комментарий от Torvus

> И кроме явного переописания перегружаемых методов базового класса ниодин не работает

И не будет работать. Переписывай, раз такова "прихоть заказчика". :-)

smh ★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.