考虑以下头文件。
在我的Object.h
#ifndef OBJECT_H_
#define OBJECT_H_
#include <iostream>
template <class Policy>
class Object
{
friend Policy;
private:
Policy* p;
int hash;
public:
Object():p(new Policy(this)),hash(0){}
~Object(){delete p;}
void set(){p->setHash();}
void show() const{std::cout<<"hash = "<<hash<<std::endl;}
};
#endif // OBJECT_H_
然后我创建了两个具有不同哈希值的策略P1和P2。
在p1.h
#ifndef P1_H_
#define P1_H_
template <class Policy> class Object;
class P1
{
enum {p1 = 1};
Object<P1>* t;
public:
P1(Object<P1>* at):t(at){}
void setHash(){t->hash = p1;}
};
#endif // P1_H_
在p2.h
#ifndef P2_H_
#define P2_H_
template <class Policy> class Object;
class P2
{
enum {p2 = 2};
Object<P2>* t;
public:
P2(Object<P2>* at):t(at){}
//void setHash(){t->hash = p2;} // ** Notice here **
};
#endif // P2_H_
在main.cpp
我有
#include "Object.h"
#include "p1.h"
#include "p2.h"
int main()
{
Object<P1> t1;
t1.set();
t1.show();
Object<P2> t2;
//t2.set();
t2.show();
}
OS X上的结果:
hash = 1
hash = 0
观察:
它将编译并正常运行。请注意,Object<P2>
的定义甚至不完整。由于P2尚未定义setHash()。
如果我在主要内容中删除评论,则会报告错误。
./ Object.h:20:8:错误:'P2'中没有名为'setHash'的成员
main.cpp:12:6:注意:在成员函数'Object :: set'的实例化中请求t2.set();
问题
考虑P1或P2类中的Object成员,即使我没有在main中创建Object<P1>
或Object<P2
的实例,编译器也会为每个成员生成类定义吗?
为什么Object<P2>
可以?由于定义不完整。
答案 0 :(得分:1)
Object<P1>
和Object<P2>
内没有P1
或P2
个成员。有Object<P1>*
和Object<P2>*
个成员。指向不完整类型的指针完全可以。除非指针被取消引用,否则不会实例化类型本身。
在main
函数中,Object<P2>
是一个完整的类型,但除非被调用(或者更确切地说,技术上,使用ODR),它的非虚拟成员函数仍未实例化。这就是拥有Object<P2> t2;
但调用t2.set()
是错误的原因。
答案 1 :(得分:1)
考虑P1或P2类中的Object成员,即使我没有在main中创建
Object<P1>
或Object<P2>
的实例,编译器也会为每个成员生成类定义吗?
没有。成员为Object<P1>* t;
和Object<P1>* t;
- 他们不是static
,因此仅在创建P1
和P2
对象实例时创建,并且&#{1}} 39;重新指针,即使这样也没有创建Object<P1>*
:传递给构造函数的指针 - 可能是nullptr
/ 0
- 只是存储。
为什么对象没问题?由于定义不完整。
使用模板,函数仅在被调用时被实例化。只要它们可以正确解析,就不是错误。