【问题标题】:Forward declaration and delete转发声明和删除
【发布时间】:2013-05-17 17:26:56
【问题描述】:

我的老师让我做一个期末作业。我需要用 C++ 列出一些东西(不能使用 boost、STL 等)。我的 Stuff 类必须在 List 类之后定义。我尝试过的小样本:

#include <cstdlib>
#include <iostream>
#include <string>
using namespace std;

class Stuff;

class List
{
    private :

        Stuff *s;
        int n;

    public :

        List(int n)
        {
            this->n = n;
            s = new Stuff[n];
        }

        ~List()
        {
            delete[] s;
            s = NULL;
            n = 0;
        }

};

class Stuff
{
    private :

        string name;
        double price;

    public :

        Stuff(){}
};

int main(int argc, char **argv)
{
    return 0;
}

我知道:

"如果被删除对象的类类型不完整 删除并且完整的类有一个非平凡的析构函数或 释放函数,行为未定义。”

但是那我该怎么做呢?有任何想法吗?请记住,我不能使用 boost、STL 等。而且必须在 List 类之后定义 Stuff 类。我只是不知道...

【问题讨论】:

  • 这太荒谬了。教师在编写C++时如何禁止使用C++标准库?要求他们编写一个打印“Hello World”的程序,而不使用System.*等标准Java包,JNI也是不允许的。
  • gcc 不会编译此代码,原因与您在引用中提到的类似。
  • “必须在 List 类之后定义东西类”。这是
  • @VladLazarenko - 在学习数据结构时,自己编写可以帮助您理解它们。
  • @AndyThomas-Cramer,绝对正确。这就是为什么我看到这么多程序员使用基本结构但不知道如何实现它们或它们是如何工作的。人们可能会提出他们不应该知道的论点 - 但一位优秀的工程师将能够为工作选择正确的工具,因为他们知道自己是如何工作的。

标签: c++ forward-declaration


【解决方案1】:

要使这段代码工作,您需要在定义List 类构造函数和析构函数之前定义Stuff

所以:

class Stuff;

class List
{
    private :

        Stuff *s;
        int n;

    public :
        List(int n);
        ~List();

};

class Stuff
{
    private :

        string name;
        double price;

    public :

        Stuff(){}
};

List::~List()
{
    delete[] s;
    s = NULL;
    n = 0;
}
List::List(int n)
{
    this->n = n;
    s = new Stuff[n];
}

【讨论】:

  • 显然要求是类 Stuff 必须在类 List 之后定义。
  • 在我的例子中。 ISN'T 类的构造函数和析构函数。但除非我们想要无法编译或复杂得多的代码,否则我看不到一个合理的解决方案。我认为期望学生以扩展/改变语言工作方式的方式重写编译器是不合理的。要使new Stuff[n] 工作,Stuff 必须是完全定义的类。
  • 谢谢。我想我会按照你的建议去做,非常感谢!:)
  • [不写新的编译器,你的意思是? ;)]
【解决方案2】:

模板呢?

template<class T>
class List
{
private :

    T *s;
    int n;

public :

    List(int n)
    {
        this->n = n;
        s = new T[n];
    }

    ~List()
    {
        delete[] s;
        s = NULL;
        n = 0;
    }
};

class Stuff
{
private :

    string name;
    double price;

public :

    Stuff(){}
    ~Stuff(){}
};


int main(int argc, char **argv)
{
    List<Stuff> list(4);
    return 0;
}

【讨论】:

  • @brian 我喜欢这个游戏!每个人都试图猜测你想要什么,而你只是不停地说不!这很有趣,我无事可做。
【解决方案3】:

您必须将List 声明放在头文件中并将实现放入源文件中,其中Stuff 定义可用(#include "Stuff.h"),您可以删除Stuff

或者你可以在同一个文件中实现List,但是在Stuff声明之后,所以编译器实际上知道要删除什么

【讨论】:

    【解决方案4】:

    将声明与实现分开。虽然您不能使用 boost 等,但您可以使用单独的头文件和源文件。

    List的定义放在list.hh中,类Stuff的定义放在stuff.hh中。在类List(在list.hh中)的定义中,声明但不定义那些需要知道类Stuff的成员函数。将这些函数定义放在源文件 list.cpp 中。此源文件将 #include list.hh 和 stuff.hh。

    【讨论】:

      【解决方案5】:

      class Stuff; 将其替换为实际实现的代码。 class Stuff;是前向声明,表示可以引用class Stuff但不能使用。

      这里有两个解决方案:


      class Stuff {
      private :
          string name;
          double price;
      public :
          Stuff(){}
      };
      
      class List
      {
      private :
          Stuff *s;
          int n;
      public :
          List(int n) {
              this->n = n;
              s = new Stuff[n];
          }
          ~List() {
              delete[] s;
              s = NULL;
              n = 0;
          }
      };
      

      class Stuff;
      
      class List
      {
      private :
          Stuff *s;
          int n;
      public :
          List(int n);
          ~List();
      }
      
      class Stuff {
      private :
          string name;
          double price;
      public :
          Stuff(){}
      };
      
      List::List(int n) {
          this->n = n;
          s = new Stuff[n];
      }
      List::~List() {
          delete[] s;
          s = NULL;
          n = 0;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-02-28
        • 2011-02-04
        • 2021-06-25
        • 2017-10-14
        • 1970-01-01
        • 1970-01-01
        • 2022-10-05
        • 1970-01-01
        相关资源
        最近更新 更多