Следующий код находится в том же заголовочном файле
#include <iostream>
class B
{
public:
void doSth()
{
A::func(1);
}
};
class A
{
public:
static void func(int a)
{
std::cout<<"a = "<< a <<std::endl;
}
};
Если класс A
определен после класса B
, как указано выше, компилятор сообщит, что func не является членом «A».
Мой вопрос: можно ли как-нибудь решить эту проблему, не меняя порядок определения классов B
и A
? Например, разместить объявление класса A
где-нибудь над классом B
? Спасибо.
Переместить определения функций-членов за пределы классов
#include <iostream>
class B {
public:
void doSth();
};
class A {
public:
static void func(int a) { std::cout << "a = " << a << std::endl; }
// Optional: static void func(int a);
};
void B::doSth() { A::func(1); }
// // static
// void A::func(int a) { std::cout << "a = " << a << std::endl; }
Странно, это должно работать, но в моем реальном коде он жалуется на переопределение doSth() внизу..... :(
Поскольку это заголовочный файл в вопросе ОП, он должен иметь inline
для определения B::doSth
, поэтому у него слабая связь.
Если он находится в заголовке, вам нужно использовать защиту заголовка и ключевое слово inline
.
Если вы хотите, чтобы B::doSth()
был объявлен и определен полностью внутри объявления класса B
, вам необходимо переместить полное объявление A
перед B
, например:
#include <iostream>
class A
{
public:
static void func(int a)
{
std::cout << "a = " << a << std::endl;
}
};
class B
{
public:
void doSth()
{
A::func(1);
}
};
В противном случае, если вам не нужно, чтобы B::doSth()
полностью находился внутри объявления класса B
, вы можете разделить его объявление и определение, а затем переместить определение после объявления класса A
, например:
#include <iostream>
class B
{
public:
void doSth();
};
class A
{
public:
static void func(int a)
{
std::cout << "a = " << a << std::endl;
}
};
inline void B::doSth()
{
A::func(1);
}
Предпочтительно, чтобы определения методов, которых нет в объявлении класса, были реализованы в отдельных файлах .cpp
, например:
А.х.
#ifndef A_H
#define A_H
class A
{
public:
static void func(int a);
};
#endif
A.cpp
#include <iostream>
#include "A.h"
void A::func(int a)
{
std::cout << "a = " << a << std::endl;
}
Б.х.
#ifndef B_H
#define B_H
class B
{
public:
void doSth();
};
#endif
Б.cpp
#include "B.h"
#include "A.h"
void B::doSth()
{
A::func(1);
}
Обратите внимание: если вы оставите определение функции в заголовочном файле, но вне определения класса, оно должно быть отмечено inline
(т. е. inline void B::doSth() { ... }
). Невыполнение этого требования приведет к нарушению ODR, если заголовок включен в несколько единиц перевода.
Если вы хотите, чтобы B::doSth()
был определен в строке, вы должны переместить объявление A
перед B
: это не так. Требованием является наличие определения функции в единице перевода, inline void doSth();
во втором варианте кода будет работать.
@aschepler я перефразировал свою формулировку
Вы не можете определить класс отдельно от его «тела», но вы можете определить функцию-член класса вне определения класса.
Например:
class A
{
public:
static void func(int);
};
class B
{
public:
void doSth()
{
A::func(1);
}
};
void A::func(int a)
{
/* Implementation of the function... */
}
Вы, конечно, можете определить функцию B::doSth
и снаружи, если порядок определений классов A
и B
изменить нельзя.
Предупреждение о том, что нельзя позволять Sth делать что-либо. Часто заканчивается дуэлями на световых мечах, мощными взрывами и сокрушительным разочарованием.