【问题标题】:Changing a C .inc file to a .h & .cpp将 C .inc 文件更改为 .h 和 .cpp
【发布时间】:2014-05-28 00:45:28
【问题描述】:

我有一个用 C 编写的 .inc 文件。其中包含一些定义和方法签名及其实现。

.inc 文件:

#define CONCAT(x,y)    x ## y
#define LCONCAT(x,y)  CONCAT(x,y)

#define DLIST          LCONCAT(LCONCAT(double_,LISTELEMENT),_list)
#define DELETEDFIRST   LCONCAT(delete_first_double_,LISTELEMENT)

int DELETEDFIRST (DLIST **first, DLIST **last);

int DELETEDFIRST (DLIST **first, DLIST **last)
{...}

我想把它带到 C++ 中。在我的 .h 文件中,我有定义指令和方法签名(封装在命名空间中)。在 .cpp 中我只有方法实现。

.h 文件

#define CONCAT(x,y)    x ## y
#define LCONCAT(x,y)  CONCAT(x,y)

#define DLIST          LCONCAT(LCONCAT(double_,LISTELEMENT),_list)
#define DELETEDFIRST   LCONCAT(delete_first_double_,LISTELEMENT)

namespace ListFunctions {
int DELETEDFIRST (DLIST **first, DLIST **last);
}

.cpp 文件

# include ListFunctions.h

namespace ListFunctions {
     int DELETEDFIRST (DLIST **first, DLIST **last) {...}
}

我计划在我的模块开发中使用这些列表函数。在我的 module.h 中,我定义了一个类型 double_node_list(双端),在我的 module.cpp 中,我将 LISTELEMENT 定义为“node em>”,然后包含 ListFunctions.h。但是 ListFunctions.cpp 中的相同包含会导致编译错误:

..\ListFunctions.h(86): error C2065:'double_LISTELEMENT_list' : undeclared identifier
..\ListFunctions.h(86): error C2065: 'first' : undeclared identifier 
..\ListFunctions.h(86): error C2065: 'double_LISTELEMENT_list' : undeclared identifier 
..\ListFunctions.h(86): error C2065: 'last' : undeclared identifier 
..\ListFunctions.h(86): error C2078: too many initializers

稍后我想将 c 风格的实现翻译成 c++。由于我缺乏经验,我想知道其他人是否同意我的做法。

【问题讨论】:

  • 如果您可以发布错误,这将对我们有所帮助。确保保护您的 .h 文件免受多个包含,请参阅 herehere
  • 错误:..\ListFunctions.h(86):错误 C2065:'double_LISTELEMENT_list':未声明的标识符 ...\ListFunctions.h(86):错误 C2065:'first':未声明的标识符。 ..\ListFunctions.h(86):错误 C2065:'double_LISTELEMENT_list':未声明的标识符 ...\ListFunctions.h(86):错误 C2065:'last':未声明的标识符 ...\ListFunctions.h(86):错误 C2078:初始化程序太多
  • LISTELEMENT 未知。即使我在 ListFunctions.cpp 中将其定义为“节点”,“double_node_list”仍然是一个未声明的标识符。我在我的模块中包含 ListFunctions.h 两次,在 ListFunctions.cpp 中包含一次

标签: c++ c


【解决方案1】:

停止。 很明显你知道 C,但你不知道 C++。 在尝试使用 C++ 编写代码之前先学习它。它是一种与 C 显着不同的语言,尝试将 C++ 编写为“C with stuff”会导致代码错误。

首先:你想要的几乎肯定是带有方法的 C++ class,而不是包含对数据类型(可能是结构?)进行操作的函数的命名空间。

第二:我不确定您在此处定义的所有宏都在做什么,但看起来好像您正在尝试定义一组变体函数。这个概念已经作为模板存在于 C++ 中。不要试图用宏来复制它;你只会让阅读你代码的人感到困惑。

【讨论】:

  • 嗯,我有单端和双端列表。在 C 语言中,我使用宏在这两个列表上定义了追加、前置、删除等。
  • 虽然这些宏在 C 中可能没问题(如果有点奇怪),但它们绝对不是 C++ 中问题的合适解决方案。在继续之前完全学习该语言。
  • “它是一种与 C 显着不同的语言,尝试将 C++ 编写成“C with stuff”会导致代码错误。” 我知道你的意思是说,但语言 是为将 C 代码库逐步改进为 C++ 而设计的。虽然没有人应该开始以“C with stuff minds”的 C++ 新项目,但一点一点地更新现有代码并引入“stuff”是按预期使用的。 (任何这样做的人都应该首先编写一些真正的 C++ 代码,以了解有关构建正确最终端点的一些线索。)
【解决方案2】:

至于您的特定问题,C 和 C++ 都是无效的,两者都应该调用该错误。解决方案是将此行放在函数之前,这会告诉编译器稍后将定义此结构,但现在我们需要指向它的指针或引用。

struct DLIST;

但是,您遇到的主要问题是您的目标似乎是将函数定义放在 cpp 文件中。不幸的是,这不能以通用方式在 C 或 C++ 中干净地完成。问题是您希望能够将列表专门化为各种类型(通过模板或宏),但是当您编译该 cpp 文件本身时,它无法知道要专门化列表的类型。对于 C 和 C++ 中的泛型结构,通常定义仍然必须在头文件或某种包含文件中。

还有一种替代方法,可以让您将函数定义放入 cpp 文件中,但它非常奇怪,我不建议这样做:

list_declarations.hpp

template<class LISTELEMENT>
class double_list {
    typedef LISTELEMENT value_type;
    struct iterator {
       ...iterator stuff
    };
    static int DELETEDFIRST (iterator first, iterator last);
};
extern template class double_list<int>; //declare int specialization
extern template class double_list<char>; //declare char specialization

list_definitions.cpp:

#include "list_declarations.h"

template<class LISTELEMENT>
int double_list<LISTELEMENT>::DELETEDFIRST(
    double_list<LISTELEMENT>::iterator first, 
    double_list<LISTELEMENT>::iterator last)
{
    ...implementation
}

template class double_list<int>; //define int specialization
template class double_list<char>; //define char specialization
//note that all of these _must_ be in the same file as the function definitions

在 C++ 中创建泛型列表的常规方法大致如下:

#pragma once

template<class LISTELEMENT, class allocator=std::allocator<LISTELEMENT>>
class double_list {
public:
    typedef allocator allocator_type;
    typedef typename allocator::value_type value_type;
    typedef typename allocator::reference reference;
    typedef typename allocator::const_reference const_reference;
    typedef typename allocator::difference_type difference_type;
    typedef typename allocator::size_type size_type;

    class iterator {
        DLIST * current;           
        explicit iterator(DLIST* c);
    public:
        typedef LISTELEMENT value_type;
        typedef LISTELEMENT& reference;
        typedef LISTELEMENT* pointer;
        typedef std::ptrdif_t difference_type;
        typedef std::bidirectional_iterator_tag iterator_category;
        iterator();
        iterator& operator++(); //prefix increment
        iterator operator++(int); //postfix increment
        iterator& operator--(); //prefix decrement
        iterator operator--(int); //postfix decrement
        reference operator*() const;
        pointer operator->() const;
        friend bool operator==(const iterator&, const iterator&);
        friend bool operator!=(const iterator&, const iterator&); 
        friend void swap(iterator& lhs, iterator& rhs);
    };
    class const_iterator { 
        const DLIST * current;           
        explicit iterator(const DLIST* c);
    public:
        const_iterator(iterator c);
        ...see above
    };

    double_list();
    double_list(const double_list& rhs);
    ~double_list();
    double_list& operator=(const double_list& rhs);

    int delete_first(iterator first, iterator last);
private:
    pointer first;
    pointer last;
};

加上任何其他对Writing your own STL Container 感兴趣的成员。由于它是一个模板类,所有函数定义都必须在标题中。显然,这与 C 方式显着不同。

【讨论】:

  • 您的假设是正确的。我有两种类型的列表,我想为其分离实现。一种是单联的,另一种是双联的。你有什么推荐的?
  • @AvishekDutta:说实话?只需使用std::vector
  • 我需要对我的容器进行插入排序。
  • @AvishekDutta:您可以对任何顺序容器进行插入排序。使用std::vector
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多