让我们从一个无需做任何有用的事情即可构建和运行的最小程序开始。
#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();
}