C++类声明和命名空间

发布于 10-13 16:59 字数 1494 浏览 4 评论 0原文

我在尝试编写的 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 的成员我不想将类声明本身放在标头中的原因是(据我所知)它会包含所有私有和类似的内容,

也许这只是 我想隐藏的。我,但下面的头文件看起来“不好”,至少作为“接口规范”。它公开了 A 的一些内部结构,而库的用户不需要了解这些内部结构。

// 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;
    }
};

如果可能的话,这是公认的方法吗?

I'm having an issue with a C++ library I'm trying to write. It's the usual setup, one cpp file, one header file. I want the header file to only expose the parts that are meant to be used (I have an abstract base class for instance, I don't want in the header file). So far, I'm just working with a single file (I assume this should make no difference, as includes are done by the preprocessor, which doesn't care about anything).

You'll note that the "header file" is spread over two spots, before and after the header implementation file.

#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());
}

So, naturally, I'd like my header file to contain just

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

But my compiler does not like this (it complains that returnT is not a member of foo::A<T>. The reason I don't want to put the class declaration itself in the header is that then it would (as I understand it), contain all the private and similar stuff, which I'd like to hide.

Maybe it's just me, but the following header file seems "bad", at least as an "interface specification." It exposes some of the internals of A, which a user of the lib would not need to know about.

// 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;
    }
};

Is this the accepted way of doing it? I'd like a more abstract header file, if at all possible.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

丢了幸福的猪2024-10-20 16:59:16

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

对于“为什么?”我建议阅读 "为什么我不能分离模板的定义类的声明并将其放入 .cpp 文件中?”


我可能误读了你的问题。为了解决您可能提出的问题,这是无效的:

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

它无效的原因与无效的原因相同:

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

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

You cannot separate the definition of a template from its declaration. They both have to go into the header file together.

For "why?" I recommend reading "Why can't I separate the definition of my templates class from its declaration and put it inside a .cpp file?".


I may have misread your question. To address what may also be your question, this is not valid:

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

It is not valid for the same reason that this is not valid:

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

Member functions must be declared inside the definition of the class.

凤舞天涯2024-10-20 16:59:16

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

I。
如果您想将该类的实例放入堆栈中(就像在 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();
  }
}

顺便说一句:建议使用智能指针...

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>;
  // ...
}

There are two problems with .cpp files you are dealing here:

I.
If you want to put an instance of that class on the stack (like you do in your main()) the compiler needs to know the size of the class (to allocate enough memory). For that it needs to know the members and by that the complete declaration.

The only way to hide the class' layout away is to built up an interface and a factory method/function and put the instance on the heap in the factory.

As an example (without the template; see below to know why):

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

      static IA *Create();
  };
}

In your .cpp you then do:

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: Using smart pointers would be suggested...

II.
Since you are using a template the method definitions must be either visible via header file or explicitly instantiated for a specific set of types.

So you can split up your code into a lib.h and a 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>();
  }
}

so you include the lib_impl.h where ever you need the impleemntations.
To use the explicit instantiations add a lib.cpp and just let that file allow to include 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>;
  // ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文