Давайте начнем с минимальной программы, которая собирает и запускает, не делая ничего полезного.
#include <string>
class Interface
{
};
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() {}
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}
Вы заметите, что есть немного изменений в вашем опубликованном коде, чтобы добраться до этого базового уровня.
Interface
пусто.
- Функции-члены
Service
находятся в разделе public
. Конструктор по умолчанию и деструктор Service
имеют пустую реализацию.
- Конструктор по умолчанию и деструктор
MyService
находятся в разделе public
класса и имеют пустые реализации.
MyService::init()
имеет пустую реализацию.
Теперь мы можем начать добавлять больше кода.
Я изменил MyService::init()
на:
void init() { x.init(this); }
Без других изменений я получил следующую ошибку компилятора.
socc.cc: In member function ‘virtual void MyService::init()’:
socc.cc:25:23: error: ‘class Interface’ has no member named ‘init’
void init() { x.init(this);}
Теперь Interface
необходимо обновить с помощью функции init
.
Я добавил фиктивную реализацию, чтобы продвинуть процесс вперед.
class Interface
{
public:
template <class T> bool init(T *_Service) { return true; }
};
Время добавить что-нибудь полезное к Interface::init()
. Меняя его на
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
выдает следующую ошибку компилятора, что неудивительно.
socc.cc: In instantiation of ‘bool Interface::init(T*) [with T = MyService]’:
socc.cc:31:32: required from here
socc.cc:8:23: error: ‘AttachService’ was not declared in this scope
AttachService(*_Service);
~~~~~~~~~~~~~^~~~~~~~~~~
Время добавить AttachService
. Изменение Interface
на (закрытие совпадает с тем, что у вас есть)
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = *_Service;
}
protected:
template<typename T> static T m_AttachedService;
};
выдает следующую ошибку компилятора.
socc.cc: In instantiation of ‘void Interface::AttachService(T) [with T = MyService]’:
socc.cc:8:10: required from ‘bool Interface::init(T*) [with T = MyService]’
socc.cc:39:32: required from here
socc.cc:14:33: error: no match for ‘operator*’ (operand type is ‘MyService’)
m_AttachedService<T> = *_Service;
^~~~~~~~~
Это имеет смысл. В AttachServie
, _Service
не является указателем.
Изменение Inteface::AttachService
на:
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
устраняет ошибку компилятора, но есть ошибка компоновщика.
:socc.cc:(.rdata$.refptr._ZN9Interface17m_AttachedServiceI9MyServiceEE[.refptr._ZN9Interface17m_AttachedServiceI9MyServiceEE]+0x0): undefined reference to `Interface::m_AttachedService<MyService>'
collect2: error: ld returned 1 exit status
Это имеет смысл, поскольку мы не определили переменную-член static
.
Добавление следующей строки
template<typename T> T Interface::m_AttachedService;
сразу после определения Interface
устраняет ошибку компоновщика.
Ниже приведена следующая версия полной программы, которая успешно собирается и работает, даже если она по-прежнему не помогает.
#include <string>
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
protected:
template<typename T> static T m_AttachedService;
};
template<typename T> T Interface::m_AttachedService;
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() { x.init(this); }
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}
Время добавить вашу версию AttachedService
в Interface
template <typename T> T AttachedService() { return m_AttachedService; }
Это приводит к следующей ошибке компилятора.
socc.cc: In member function ‘T Interface::AttachedService()’:
socc.cc:17:73: error: missing template arguments before ‘;’ token
template <typename T> T AttachedService() { return m_AttachedService; }
Это имеет смысл, поскольку m_AttachedService
является не переменной-членом, а шаблоном переменной-члена.
Изменив это на
template <typename T> T AttachedService() { return m_AttachedService<T>; }
удаляет эту ошибку.
Теперь последний кусок в Interface
. Вложенный класс InterfaceListener
, который вы опубликовали, звучит правильно. У вас есть
class InterfaceListener
{
void Received()
{
int a = 1;
std::string b = "hello";
AttachedService().setA(a);
m_AttachedService.setB(b);
};
};
Проблемы в этом классе:
AttachedService()
неправильно, так как это шаблон функции-члена. Вы должны предоставить параметр шаблона, чтобы использовать его.
- Кроме того,
AttachedService()
не является static
функцией-членом. Вам нужен экземпляр Interface
, чтобы сделать этот вызов.
m_AttachedService
не является переменной-членом. Это шаблон переменной члена. Вы должны предоставить параметр шаблона, чтобы использовать его.
- Функции
setA()
и setB()
действительны, только если параметром шаблона является MyService
. Не имеет смысла иметь в этой функции код, специфичный для типа.
Я оставлю вам на размышление над тем, как вы собираетесь использовать InterfaceListener
, и определите его функции соответствующим образом. До тех пор у меня собирается и запускается следующая программа.
#include <string>
class Interface
{
public:
template <class T> bool init(T *_Service)
{
AttachService(*_Service);
return true;
}
template <typename T> void AttachService(T _Service)
{
m_AttachedService<T> = _Service;
}
template <typename T> T AttachedService() { return m_AttachedService<T>; }
protected:
template<typename T> static T m_AttachedService;
};
template<typename T> T Interface::m_AttachedService;
class Service
{
protected:
Service() {}
~Service() {}
virtual void init() = 0;
};
class MyService : public Service, public Interface
{
private:
int A;
std::string B;
protected:
Interface x;
public:
MyService() {}
~MyService() {}
void init() { x.init(this); }
void setA(int a) { A = a; }
void setB(std::string b) { B = b; }
};
int main()
{
MyService myserv;
myserv.init();
}