zoukankan      html  css  js  c++  java
  • 关于C++中的前置声明(附程序运行图)

     TZ实验于华中农业大学逸夫楼2017.3.10

    在编写C++程序的时候,偶尔需要用到前置声明(Forward declaration)。下面的程序中,带注释的那行就是类B的前置说明。这是必须的,因为类A中用到了类B,而类B的声明出现在类A的后面。如果没有类B的前置说明,下面的程序将不同通过编译,编译器将会给出类似“缺少类型说明符”这样的出错提示。

    代码一:

    // ForwardDeclaration.h

    #include <iostream>

    using namespace std;

    class B;             // 这是前置声明(Forward declaration)

    class A

    {

    private:

             B* b;

    public:

             A(B* b):b(b)

             {

             }

             …

    };

     

    class B

    {

             …

    };

    // Main.cpp

    #include "ForwardDeclaration.h"

    int main(int argc, char** argv)

    {

             B* b = new B();

             A* a = new A(b);

     

             delete a;

             delete b;

     

             return 0;

    }

    上面程序可以顺利编译和运行(几乎没有做什么,也没有输出)。

    是不是有了前置说明就万事大吉了呢?我们看看下面的代码(带阴影部分的代码是新增加的):

    代码二:

    // ForwardDeclaration.h

    #include <iostream>

    using namespace std;

     

    class B;             // 这是前置声明(Forward declaration)

     

    class A

    {

    private:

             B* b;

    public:

             A(B* b):b(b)

             {

             }

     

             void someMethod()

             {

                       b->someMethod();                                                  // (1)

             }

    };

     

    class B

    {

    private:

    public:

             void someMethod()

             {

                       cout << "something happened..." << endl;

             }

    };

    // Main.cpp

    #include "ForwardDeclaration.h"

     

    int main(int argc, char** argv)

    {

             B* b = new B();

             A* a = new A(b);

     

             a->someMethod();

     

             delete a;

             delete b;

     

             return 0;

    }

    一编译,发现代码(1)处出错。出错提示往往包括(不同的编译器给出的提示会有所不同):

    1. 使用了未定义的类型B;
    2. “->somemethod”的左边必须指向类/结构/联合/泛型类型

    原因:

    1. (1)处使用了类型B的定义,因为调用了类B中的一个成员函数。前置声明class B;仅仅声明了有一个B这样的类型,而并没有给出相关的定义,类B的相关定义,是在类A后面出现的,因此出现了编译错误;
    2. 代码一之所以能够通过编译,是因为其中仅仅用到B这个类型,并没有用到类B的定义。

    解决办法是什么?

    将类的声明和类的实现(即类的定义)分离。如下所示:

    // ForwardDeclaration.h   类的声明

    #include <iostream>

    using namespace std;

     

    class B;             // 这是前置声明(Forward declaration)

     

    class A

    {

    private:

             B* b;

    public:

             A(B* b);

             void someMethod();

    };

     

    class B

    {

    private:

    public:

             void someMethod();

    };

    // ForwardDeclaration.cpp        类的实现

    #include "ForwardDeclaration.h"

     

    A::A(B* b):b(b)

    {

    }

     

    void A::someMethod()

    {

             b->someMethod();

    }

     

     

    void B::someMethod()

    {

             cout << "something happened..." << endl;

    }

    // Main.cpp

    #include "ForwardDeclaration.h"

     

    int main(int argc, char** argv)

    {

             B* b = new B();

             A* a = new A(b);

     

             a->someMethod();

     

             delete a;

             delete b;

     

             return 0;

    }

    结论:

    前置声明只能作为指针或引用,不能定义类的对象,自然也就不能调用对象中的方法了。

    而且需要注意,如果将类A的成员变量B* b;改写成B& b;的话,必须要将b在A类的构造函数中,采用初始化列表的方式初始化,否则也会出错。

    文章来源:http://patmusing.blog.163.com/blog/static/135834960201038113714199/

  • 相关阅读:
    上学要迟到了【最短路转化】
    解方程【狄利克雷卷积+莫比乌斯反演+积性函数】
    FFT
    min25 筛
    Easy【生成函数】
    CF1406D-Three Sequences
    Alice和Bob赌糖果【赌徒破产模型】
    记MySQL自增主键修改无效的问题
    JVM学习笔记(十一、JDK分析工具)
    JVM学习笔记(十、GC3-垃圾回收机制)
  • 原文地址:https://www.cnblogs.com/acm-icpcer/p/6530842.html
Copyright © 2011-2022 走看看