对C ++类的使用感到困惑

时间:2015-11-11 02:27:17

标签: c++

以下是使我对类的使用感到有些困惑的代码。

    template <int dim>
    class FEM
    {
    public:
      FEM (unsigned int order,unsigned int problem); 
      ~FEM(); 
    ...
    FESystem<dim>        fe;
    DoFHandler<dim>      dof_handler;
    ...
    }

    template <int dim>
    FEM<dim>::FEM(unsigned int order,unsigned int problem)
    :
    fe (FE_Q<dim>(order), dim), 
    dof_handler (triangulation)
    {
    ...
    }

这里“FESystem”,“DoFHandler”和“FE_Q”是头文件中的一些预定义类。我对此代码有几个问题:

(1)为什么构造函数“fe”和“dof_handler”在类“FE”本身之外声明,它们是否可能在第一个括号内声明,即在“FE”类定义中?

(2)代码中双重冒号和冒号“ :: ”和“”的含义分别是什么?他们为什么在这里使用?冒号“:”是否意味着继承?

    template <int dim>
    FEM<dim>::FEM(unsigned int order,unsigned int problem)
    :
    fe (FE_Q<dim>(order), dim), 
    dof_handler (triangulation){...}

我是C ++的新手。谁能给我一些帮助?非常感谢!

3 个答案:

答案 0 :(得分:0)

双冒号用于指定您正在为特定类实现函数。在这种情况下,它是FEM类的构造函数的实现。如果FEM有一个方法DoIt(),实现可能如下所示:

template<int dim>
int FEM<dim>::DoIt() { return 1; }

单个结肠&#34;:&#34;如果要将参数直接传递给成员变量的构造函数,则与构造函数一起使用。所以在上面的代码中,FEM的构造函数将参数传递给它的成员fe。 FESystem必须有一个构造函数,它取FE_Q&lt;&lt; dim&gt;&gt;,以及作为参数的int。它也向DoFHandler传递了一些东西,但它不清楚代码中triangulation是什么。这似乎不会编译。

答案 1 :(得分:0)

  

(1)为什么构造函数“fe”和“dof_handler”在类“FE”本身之外声明,它们是否可能在第一个括号内声明,即在“FE”类定义中?

是的,对于模板化类,它们可以位于“FE”模板类定义的内部或外部。有些人更喜欢外面的可读性,他们可以看到每个功能的列表,而不必向下滚动太远。

但是,对于常规的非模板化类,将您的类外实现放在相应的源(.cpp)文件中,而不是在类或类下面。原因是,包含您的标题的每个其他类将反复编译相同的实现,这将减慢您的构建速度并生成巨大的二进制文件。对于模板类,你别无选择。它们必须由每个翻译单元编译,因为模板化将由编译器代码生成。

  

(2)代码中双冒号和冒号“::”和“:”分别是什么意思?他们为什么在这里使用?冒号“:”是否意味着继承?

双冒号是你的范围。它可以是命名空间或类名。这使得可以从两个不同的类中具有两个名称完全相同的函数而不会发生名称冲突。它对覆盖非常有用。

例如,您可以在标题中包含此内容:

class A
{
public:
    virtual foo(int a);
};

class B : public A
{
public:
    virtual foo(int a);
};

并在您的来源(.cpp)文件中包含该内容:

A::foo(int a) {
    printf("Hello World from A::foo(%s)\n", a);
}

B::foo(int a) {
    A::foo(a); // calling the super class's foo(int)
    printf("Hello World from B::foo(%s)\n", a);
}

如果我们没有范围,我们将无法区分这两个功能。在Java或C#中,这已被简化为单个点。

在这种特殊情况下,单个冒号是C ++构造函数的一个非常特殊的特性。只有构造函数才能做到这一点。这称为'初始化程序',它们是一个简洁的小优化,可用于为构件变量设置默认值,而不是在构造的函数范围内手动执行。

例如,如果你在这里有这个课:

class A
{
public:
    A(); // constructor

    int a;
    float b;
};

您可能希望在.cpp源文件中编写这样的构造函数:

A::A() {
    a = 0;
    b = 0.0;
}

但是,使用初始化,您可以这样写:

A::A() :
    a(0),
    b(0.0)
{
}

初始化内存的速度应该更快,只要你按照它们在标题中声明的顺序初始化它们的顺序。在此特定示例中,如果您在b之前初始化a,则优化将无效。

C ++起初可能很难理解,但它是一种非常强大的语言,学习起来真的很有趣。

答案 2 :(得分:-1)

C ++中的类方法通常在类定义之外定义。这与Java,Python等不同。它有一个很好的理由:类的定义只包含其方法的原型,即所谓的声明。这是程序其他部分所需的所有信息,以了解特定类的外观。类定义保存在头文件中。并且这些标头需要包含在使用该类的每个源代码中。 方法的实际实现通常保存在单独的文件中。因此,类名和前面的双冒号用于标识它们所属的类。 头文件中的源代码将使用每个使用这些类定义的代码进行编译。方法背后的实际程序可以单独编译,并在链接阶段添加。