【问题标题】:C++ Interface declaration/definition and usageC++接口声明/定义和使用
【发布时间】:2013-07-11 14:33:13
【问题描述】:

我正在尝试通过使用接口来创建一个非常模块化的程序。来自 C# 背景,我会将接口用作变量类型,这样我就可以使用多态性,允许我自己/其他人将从该接口继承的许多不同对象传递给函数/变量。 但是,尝试在 C++ 中执行此操作时,我遇到了许多奇怪的错误。我在这里做错了什么?

我希望能够拥有接口类型的变量。但是,以下会产生编译错误。我认为编译器认为我的 ErrorLogger 类是抽象的,因为它继承自抽象类或其他东西。

ILogger * errorLogger = ErrorLogger();

error C2440: 'initializing' : cannot convert from 'automation::ErrorLogger' to 'automation::ILogger *'

如果我以错误的方式处理这个问题,即使是在设计方面,我也在学习,并且很乐意听取任何和所有建议。

ILogger.h:

#ifndef _ILOGGER_H_
#define _ILOGGER_H_

namespace automation
{
    class ILogger
    {
    public:
        virtual void Log(const IError &error) = 0;
    };
}
#endif

ErrorLogger.h:

#ifndef _ERRORLOGGER_H_
#define _ERRORLOGGER_H_
#include "ILogger.h"
#include "IError.h"

/* Writes unhandled errors to a memory-mapped file.
 * 
**/

namespace automation
{
    class ErrorLogger : public ILogger
    {
    public:
        ErrorLogger(const wchar_t * file = nullptr, const FILE * stream = nullptr);
        ~ErrorLogger(void);
        void Log(const IError &error);
    };
}
#endif

ErrorLogger.cpp:

#include "stdafx.h"
#include "ErrorLogger.h"
#include "IError.h"

using namespace automation;

ErrorLogger::ErrorLogger(const wchar_t * file, const FILE * stream)
{

}

void ErrorLogger::Log(const IError &error)
{
    wprintf_s(L"ILogger->ErrorLogger.Log()");
}

ErrorLogger::~ErrorLogger(void)
{
}

IError.h:

#ifndef _IERROR_H_
#define _IERROR_H_

namespace automation
{
    class IError
    {
    public:
        virtual const wchar_t *GetErrorMessage() = 0;
        virtual const int &GetLineNumber() = 0;
    };
}
#endif

编译错误:

谢谢, -弗朗西斯科

【问题讨论】:

  • 在 C++ 中,多态性需要使用指针(可能是智能指针)或引用。
  • 编译错误很小。你能把它们作为纯文本而不是图片吗?
  • 请发布实际代码而不是图片。
  • @CaptainObvlious:好吧,即使你的课程是具体的并且你做了Derived d; Base b = d,你得到的是切片。所以是的,在这种情况下,问题还在于Base 是抽象的,但这只是故事的一半;)
  • 正如@CaptainObvlious 所说,文本形式的实际代码很有帮助。原因是我们可以用鼠标把它捡起来,粘贴到一个测试 *.cpp 文件中,在回答之前自己尝试一下。

标签: c++ interface implementation


【解决方案1】:

ILogger * errorLogger = ErrorLogger(); errorLogger是一个指针,需要用new operator初始化。

定义指向派生类的基指针的正确方法是:

automation::ILogger * errorLogger = new automation::ErrorLogger();
//                                  ^^^^

在现代 C++ 中更好地使用智能指针:

#include <memory>
std::unique_ptr<automation::ILogger> errorLoggerPtr(new automation::ErrorLogger());

您还需要在ILogger.h 中包含IError.h

#include "IError.h"

其他建议:

1 使用 fstream 而不是 FILE 2 使用 std::wstring 代替 wchar_t * 2 在 cpp 文件中,不要调用

using namespace automation;

而是用命名空间包装函数定义,就像你在头文件中所做的那样:

namespace automation
{
    ErrorLogger::ErrorLogger(const std::wstring& file, std::ofstream& stream)
    {
    }
}

重点是不要把C++代码和C代码混在一起,C++类如string,fstream提供RAII,更安全,更易用。

【讨论】:

  • 谢谢@billz。虽然这确实有效,但这是否意味着我无法将 ILogger 指针初始化为堆栈中的 ErrorLogger?因为 new 关键字在堆中分配它不是吗?
  • 您是否在 ILogger.h 中“#include "IError.h"?
  • 我认为使用智能指针是正确的方法。它们可以多态使用。
  • 感谢您的建议,我没有使用智能指针的原因是出于代码可移植性的原因,同样的原因是我没有使用#pragma 等。只要仍然有一个相当简单的方法来能够将代码移植到 GC++ 我会考虑使用所有这些添加。
【解决方案2】:

你需要在ILogger.h头文件中#include "IError.h"

【讨论】:

  • 啊,那我真傻。我的另一个问题呢? “能够有接口类型的变量。但是,下面也会产生编译错误。我认为编译器认为我的ErrorLogger类是抽象的,因为它继承自抽象类什么的。ILogger logger = ErrorLogger(); 如果我是以错误的方式解决这个问题,即使是在设计方面,我也在学习,并且很乐意听取任何和所有建议。”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多