• 交叉引用的解决方法——类声明的应用


    交叉引用的解决方法

    什么是交叉引用?

    什么是交叉引用?一言以蔽之,就是:A类中包括B类的对象。B类中包括A类的对象。

    以一场景为例

    我们先来看一个场景。如果有一个电子文档(Document)、一个文档下有多个页(Page),每一个页下有多个文本单元(TextUnit,表示文档内元素的基本单位),一个文档中的全部文本单元对象都有唯一的ID。这样每创建一个文本单元时都要为其设置一个唯一的ID。我们在Document类中就须要一个生成唯一ID的方法为全部的文本单元创建唯一标识。于是我们就会有以下的类关系设计图:

    这里写图片描写叙述
    图1 :类的关系图

    于是我们想当然的会有这样的代码:

    TextUnit.h:

    #pragma once
    class TextUnit
    {
    public:
        TextUnit(void);
        TextUnit(int id);
        ~TextUnit(void);
    
    public:
        int GetId() { return m_id; }
        void SetId(int id) { m_id = id; }
    
    private:
        int m_id;           //文本对象的唯一标识
    };

    TextUnit.cpp:

    #include "StdAfx.h"
    #include "TextUnit.h"
    
    TextUnit::TextUnit(void)
    {
    }
    
    TextUnit::TextUnit( int id ) : m_id(id)
    {
    }
    
    
    TextUnit::~TextUnit(void)
    {
    }

    Page.h:

    #pragma once
    
    #include <vector>
    #include "TextUnit.h"
    #include "Document.h"
    
    typedef std::vector<TextUnit*>  VecTextUnit;
    
    class Page
    {
    public:
        Page(Document* pDocument);
        ~Page(void);
    
    public:
        //加入一个文本单元
        TextUnit* AddTextUnit();
    
    private:
        Document*           m_pDocument;        //文档对象,用于获得ID
        VecTextUnit*        m_pvecTextUnits;    //文本单元对象
    };

    Page.cpp:

    #include "StdAfx.h"
    #include "Page.h"
    
    Page::Page(Document* pDocument) : m_pDocument(pDocument), m_pvecTextUnits(new VecTextUnit)
    {
    }
    
    Page::~Page(void)
    {
        for (VecTextUnit::iterator iter = m_pvecTextUnits->begin(); iter != m_pvecTextUnits->end(); ++ iter )
        {
            delete[] *iter;
            *iter = NULL;
        }
        m_pvecTextUnits->clear();
        delete[] m_pvecTextUnits;
        m_pvecTextUnits = NULL;
    }
    
    TextUnit* Page::AddTextUnit()
    {
        int id = m_pDocument->GenerateId();
        TextUnit* pTextUnit = new TextUnit(id);
        if (pTextUnit == NULL)
        {
            return NULL;
        }
        m_pvecTextUnits->push_back(pTextUnit);
        return pTextUnit;
    }

    Document.h:

    #pragma once
    
    #include <vector>
    #include "Page.h"
    
    typedef std::vector<Page*>  VecPage;
    
    class Document
    {
    public:
        Document(void);
        ~Document(void);
    
    public:
        //生成本文档内唯一的文本对象ID
        int GenerateId();
        //加入一页
        Page* AddPage();
    
    private:
        static int      s_id;               //用于生成唯一的ID
        VecPage*        m_pvecPages;        //全部的页
    };

    Document.cpp:

    #include "StdAfx.h"
    #include "Document.h"
    
    int Document::s_id = 0;
    
    Document::Document(void) : m_pvecPages(new VecPage)
    {
    }
    
    Document::~Document(void)
    {
        for (VecPage::iterator iter = m_pvecPages->begin(); iter != m_pvecPages->end(); ++ iter )
        {
            delete[] *iter;
            *iter = NULL;
        }
        m_pvecPages->clear();
        delete[] m_pvecPages;
        m_pvecPages = NULL;
    }
    
    int Document::GenerateId()
    {
        return s_id ++;
    }
    
    Page* Document::AddPage()
    {
        Page* pPage = new Page(this);
        if (pPage == NULL)
        {
            return NULL;
        }
        m_pvecPages->push_back(pPage);
        return pPage;
    }

    编译

    好,代码写完了,我们对它进行编译。这时你会发现一堆的错误:

    1>d:博客文章c++高级编辑projectscrossreferencecrossreferencedocument.h(6): error C2065: ‘Page’ : undeclared identifier
    1>d:博客文章c++高级编辑projectscrossreferencecrossreferencedocument.h(6): error C2059: syntax error : ‘>’
    1>d:博客文章c++高级编辑projectscrossreferencecrossreferencedocument.h(9): error C2143: syntax error : missing ‘;’ before ‘{’

    1>d:博客文章c++高级编辑projectscrossreferencecrossreferencepage.h(12): error C2061: syntax error : identifier ‘Document’
    1>d:博客文章c++高级编辑projectscrossreferencecrossreferencepage.h(20): error C2143: syntax error : missing ‘;’ before ‘*’
    1>d:博客文章c++高级编辑projectscrossreferencecrossreferencepage.h(20): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
    1>d:博客文章c++高级编辑projectscrossreferencecrossreferencepage.h(20): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int

    原因分析

    这是由于
    1. C++中,在创建或使用一个类时。这个类必须被定义完整(就是一个完整的类型);
    2. 类的定义也能够和函数一样分成两步,先声明后定义。

    class T;    //声明一个类
    

    这样的声明也被称为前向声明。在程序中引入名字T。并指明T是一种类类型。此时的T在它被定义之前是不完整的类型(incomplete type),也就是说仅仅知道它是一种类类型,并不知道它有哪些成员,但可定义这个类型(T)的指针和引用。

    类的定义:

    class T
    {
        // todo: 定义类的成员(属性和方法)
    };
    

    仅仅有类(T)定义完毕,它才是一个完整的类型,才是可见的(才可被创建和使用)。

    而我们的程序如今就出现这样的非常有意思的状态:在定义Document时,发现Page还未定义完整(Document中有Page类型的成员);在定义Page的时候发现Document还未定义完整(Page中有Document类型的指针对象)。也就是说Document不知道Page。Page不知道Docunent,这时就像两仅仅狗打架,A狗咬着B狗的尾巴,B狗咬着A狗的尾巴。

    解决方法

    1.在Document.h文本中加入Page类的声明:calss Page; 把include “Page.h”放到Document.cpp中。


    2.Page.h文本中加入Page类的声明:calss Document; 把include “Document.h”放到Page.h中。

    代码例如以下:
    Document.h:

    #pragma once
    
    #include <vector>
    
    class Page;
    
    typedef std::vector<Page*>  VecPage;
    
    class Document
    {
    public:
        Document(void);
        ~Document(void);
    
    public:
        //生成本文档内唯一的文本对象ID
        int GenerateId();
        //加入一页
        Page* AddPage();
    
    private:
        static int      s_id;               //用于生成唯一的ID
        VecPage*        m_pvecPages;        //全部的页
    };

    Document.cpp:

    #include "StdAfx.h"
    #include "Document.h"
    #include "Page.h"
    
    int Document::s_id = 0;
    
    Document::Document(void) : m_pvecPages(new VecPage)
    {
    }
    
    Document::~Document(void)
    {
        for (VecPage::iterator iter = m_pvecPages->begin(); iter != m_pvecPages->end(); ++ iter )
        {
            delete[] *iter;
            *iter = NULL;
        }
        m_pvecPages->clear();
        delete[] m_pvecPages;
        m_pvecPages = NULL;
    }
    
    int Document::GenerateId()
    {
        return s_id ++;
    }
    
    Page* Document::AddPage()
    {
        Page* pPage = new Page(this);
        if (pPage == NULL)
        {
            return NULL;
        }
        m_pvecPages->push_back(pPage);
        return pPage;
    }

    Page.h:

    #pragma once
    
    #include <vector>
    #include "TextUnit.h"
    
    class Document;
    
    typedef std::vector<TextUnit*>  VecTextUnit;
    
    class Page
    {
    public:
        Page(Document* pDocument);
        ~Page(void);
    
    public:
        //加入一个文本单元
        TextUnit* AddTextUnit();
    
    private:
        Document*           m_pDocument;        //文档对象,用于获得ID
        VecTextUnit*        m_pvecTextUnits;    //文本单元对象
    };

    Page.cpp:

    #include "StdAfx.h"
    #include "Page.h"
    #include "Document.h"
    
    Page::Page(Document* pDocument) : m_pDocument(pDocument), m_pvecTextUnits(new VecTextUnit)
    {
    }
    
    Page::~Page(void)
    {
        for (VecTextUnit::iterator iter = m_pvecTextUnits->begin(); iter != m_pvecTextUnits->end(); ++ iter )
        {
            delete[] *iter;
            *iter = NULL;
        }
        m_pvecTextUnits->clear();
        delete[] m_pvecTextUnits;
        m_pvecTextUnits = NULL;
    }
    
    TextUnit* Page::AddTextUnit()
    {
        int id = m_pDocument->GenerateId();
        TextUnit* pTextUnit = new TextUnit(id);
        if (pTextUnit == NULL)
        {
            return NULL;
        }
        m_pvecTextUnits->push_back(pTextUnit);
        return pTextUnit;
    }
  • 相关阅读:
    《Effective C++》笔记
    《C++ Qt 编程视频教程》
    Windows下802.11抓包
    springcloud01_ribbon使用及原理
    springboot04_springboot特性之Actuator
    springboot04_手写实现starter实现
    linux操作01_redis服务器安装
    springboot03_核心特性及设计思想
    springboot重新认识
    springboot01_微服务架构的现状及未来【上】
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7375570.html
Copyright © 2020-2023  润新知