C ++类声明和命名空间

时间:2011-01-24 18:32:35

标签: c++ templates class namespaces header-files

我正在尝试编写一个C ++库的问题。这是通常的设置,一个cpp文件,一个头文件。我希望头文件只显示要使用的部分(例如,我有一个抽象基类,我不想在头文件中)。到目前为止,我只是处理一个文件(我认为这应该没有区别,因为包含是由预处理器完成的,它不关心任何事情。)

您会注意到“标题文件”分布在标题实现文件之前和之后的两个位置。

#include <stdio.h>

// lib.h
namespace foo {
    template <class T> class A;
}

// lib.cpp
namespace foo {
    template <class T> class A {
        private:
        T i;
        public:
        A(T i) {
            this->i = i;
        }

        T returnT() {
            return i;
        }
    };
};

// lib.h
namespace foo {
    template <class T> T A<T>::returnT();
}

// foo.cpp
void main() {
    foo::A<int> a = foo::A<int>(42);
    printf("a = %d",a.returnT());
}

所以,当然,我希望我的头文件只包含

namespace foo {
    template <class T> class A;
    template <class T> T A<T>::returnT();
}

但是我的编译器不喜欢这个(它抱怨returnT不是foo::A<T>的成员。我不想把类声明本身放在标题中的原因是它然后它(根据我的理解),包含所有私人和类似的东西,我想隐藏。

也许只是我,但是下面的头文件似乎“糟糕”,至少作为“接口规范”。它公开了A的一些内部结构,lib的用户不需要知道这些内容。

// lib.h
namespace foo {
    template <class T> class A {
        private:
        int i;
        public:
        A(T);
        T returnT();
    };
}

// lib.cpp
namespace foo {
    template <class T> A<T>::A(T i) {
        this->i = i;
    }
    template <class T> T A<T>::returnT() {
        return i;
    }
};

这是接受的方式吗?如果可能的话,我想要一个更抽象的头文件。

2 个答案:

答案 0 :(得分:5)

您无法将模板的定义与其声明分开。他们都必须一起进入头文件。

对于“为什么?”我建议阅读"Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?"


我可能误解了你的问题。要解决可能也是您的问题,这是无效的:

namespace foo {
    template <class T> class A;     
    template <class T> T A<T>::returnT(); 
} 

由于无效的原因无效:

namespace foo {
    class A;
    int A::returnT();
} 

必须在类的定义中声明成员函数。

答案 1 :(得分:2)

您在这里处理的.cpp文件存在两个问题:

予。 如果要将该类的实例放在堆栈上(就像在main()中那样),编译器需要知道类的大小(以分配足够的内存)。为此,它需要知道成员以及完整的声明。

隐藏类布局的唯一方法是构建一个接口和一个工厂方法/函数,并将实例放在工厂的堆上。

作为一个例子(没有模板;见下面知道原因):

namespace foo {
  class IA {
    public:
      virtual ~IA();
      virtual int returnT() = 0;

      static IA *Create();
  };
}

然后在.cpp中执行:

namespace foo {
  class A : public IA {
    private:
      int i;
    public:
      A() : 
        i(0) {
      }
      virtual ~A() {
      }
      virtual int returnT() {
        return i;
      }
  };
  IA::~IA() {
  }

  IA *IA::Create() {
    return new A();
  }
}

BTW:建议使用智能指针......

II。 由于您使用的是模板,因此方法定义必须通过头文件可见,或者为特定的一组类型显式实例化。

因此,您可以将代码拆分为lib.h和lib_impl.h:

lib.h:

namespace foo {
  template <typename T> class IA {
    public:
      virtual ~IA() {
      }
      virtual T returnT() = 0;

      static IA *Create();
  };
}

lib_impl.h:

namespace foo {
  template <typename T> class A : public IA<T> {
    private:
      T i;
    public:
      A() : 
        i(T()) {
      }
      virtual ~A() {
      }
      virtual T returnT() {
        return i;
      }
  };

  template <typename T> IA<T> *IA<T>::Create() {
    return new A<T>();
  }
}

所以你需要将lib_impl.h包含在需要实现的地方。 要使用显式实例化,请添加lib.cpp并让该文件允许包含lib_impl.h:

lib.cpp:

#include <lib_impl.h>
namespace foo {
  template class IA<int>;
  template class A<int>;
  template class IA<float>;
  template class A<float>;
  template class IA<char>;
  template class A<char>;
  // ...
}