29

有没有办法避免Graph::实现文件中的重复,但仍然将类拆分为头文件+实现?比如在:

头文件:

#ifndef Graph_H
#define Graph_H

class Graph {
public:
    Graph(int n);
    void printGraph();
    void addEdge();
    void removeEdge();
};

#endif

实施文件:

Graph::Graph(int n){}
void Graph::printGraph(){}
void Graph::addEdge(){}
void Graph::removeEdge(){}
4

8 回答 8

15

我猜这是为了避免大量“不必要的打字”。可悲的是,没有办法摆脱范围(正如许多其他答案告诉你的那样)但是我个人所做的是用我所有的函数原型在漂亮的行中定义类,然后复制/粘贴到实现文件中,然后 ctrl-c你的 ClassName:: 在剪贴板上,然后用 ctrl-v 运行。

于 2012-06-04T19:56:00.007 回答
13

如果您想避免在 printGraph、addEdge 等前面键入“Graph::”,那么很遗憾,答案是“否”。类似于 C# 的“部分类”功能在 C++ 中不可访问,任何类的名称(如“Graph”)都不是命名空间,而是范围。

于 2012-06-04T19:40:59.247 回答
5

不,没有。至少不是直接的。您可以使用预处理器技巧,但不要这样做

#define IMPL Graph::

IMPL Graph(int n){}
void IMPL printGraph(){}
void IMPL addEdge(){}
void IMPL removeEdge(){}

此外,您甚至不应该这样做。重点是什么。除了它是 C++ 规则之外,它还让您知道您实际上正在实现一个成员函数。

于 2012-06-04T19:41:28.873 回答
4

一种选择是using。如果您的方法定义位于从不获取#included 的 cpp 文件中,那么using是安全的(不影响其他文件):

富.h:

class FooLongNameSpecialisationsParamaters
{
    int x_;

public:

    int Get () const;
    void Set (int);
};

foo.cpp:

#include "foo.h"

using Foo = FooLongNameSpecialisationsParamaters;

int Foo::Get () const
{
    return x_;
}

void Foo::Set (int x)
{
    x_ = x;
}

主.cpp:

#include "foo.h"

int main ()
{
    //Foo foo; <-- error
    FooLongNameSpecialisationsParamaters foo;

    return 0;
}
于 2020-02-03T05:49:48.320 回答
2

不,没有办法避免它。否则,你怎么知道给定的函数定义是用于类函数还是静态函数?

于 2012-06-04T19:41:12.877 回答
2

如果您询问是否可以定义成员函数,例如Graph::printGraph不指定类名限定,那么答案是否定的,不是您想要的方式。这在 C++ 中是不可能的:

实现文件:

void printEdge(){};

以上将编译得很好,但它不会做你想要的。它不会在Graph类中以相同的名称定义成员函数。相反,它将声明并定义一个名为printEdge.

这是好的和适当的,如果从您的角度来看有点痛苦,因为您可能只想要两个具有相同名称但在不同范围内的函数。考虑:

// Header File
class A
{
  void foo();
};

class B
{
  void foo();
};

void foo();

// Implementation File
void foo()
{
}

该定义应适用于哪个范围?C++ 不限制您在不同范围内使用具有相同名称的不同函数,因此您必须告诉编译器您正在定义什么函数。

于 2012-06-04T19:46:27.917 回答
1
        //yes it is possible using preprocessor like this:

        #define $ ClassName //in .cpp 

    void $::Method1() 
    { 
    } 

    //or like this: in the header .h:

        #undef $
        #define $ ClassName' 

// but you have to include the class header in last #include in your .cpp:

        #include "truc.h"
        #include "bidule.h" ...
        #include "classname.h" 

        void $::Method() { }  

        //i was using also 
        #define $$ BaseClass 
        //with single inheritance  than i can do this: 

        void $::Method() 
        { 
        $$::Method(); //call base class method 
        } 

        //but with a typedef defined into class like this it's better to do this: 
        class Derived : Base 
        { 
        typedef Base $$;  

    }
于 2012-12-06T20:14:45.047 回答
0

编辑:我误读了你的问题。这将是您是否可以拆分头文件的问题的答案。LongClassName::抱歉,避免使用 -syntaxes对您没有帮助。

简单的答案:您可以拆分 c++ 文件,但不能拆分头文件。

原因很简单。每当您的编译器需要编译构造函数时,它都需要确切知道需要为这样的对象分配多少内存。

例如:

class Foo {
   double bar;  //8 bytes
   int goo;  //4 bytes
}

new Foo()需要分配12 bytes内存。但是如果你被允许在多个文件上扩展你的类定义,从而拆分头文件,你很容易把它弄得一团糟。你的编译器永远不会知道你是否已经告诉了它关于类的一切,或者你是否没有。代码中的不同位置可能对类有不同的定义,从而导致分段错误或神秘的编译器错误。

例如:

h1.h

class Foo {
   double bar;  // 8 bytes
   int goo;     // 4 bytes
}

h2.h: #include "h1.h"

class Foo {
   double goo;   // 8 bytes
} // we extend foo with a double.

foo1.cpp

#include "foo1.h"

Foo *makeFoo() {
   return new Foo();

}

foo2.cpp

#include "foo2.h"

void cleanupFoo(Foo *foo) {
   delete foo;
}

foo1.h

#include "h1.h"

Foo *makeFoo();

foo2.h

#include "h1.h"
#include "h2.h"

void cleanupFoo(Foo *foo)

main.cpp

#include foo1.h
#include foo2.h

void main() {
    Foo *foo = makeFoo();
    cleanupFoo(foo);
}

仔细检查如果您首先编译main.cpp到 main.o,然后编译foo1.cppfoo1.ofoo2.cppfoo2.o,最后将所有这些链接在一起会发生什么。这应该编译,但makeFoo()分配的东西然后cleanupFoo()释放。

所以你有它,随意拆分.cpp-files,但不要在头文件上拆分类。

于 2012-06-04T20:04:46.543 回答