关于这个抽象类的实现,我没有得到什么?

发布于 2024-09-02 02:12:34 字数 2064 浏览 3 评论 0原文

前言:我在 C++ 方面相对缺乏经验,所以这很可能是第一天的问题。

我正在开发一些东西,其长期目标是跨多个操作系统进行移植。我有以下文件:

Utilities.h

#include <string>

class Utilities
{
public:
    Utilities() { };
    virtual ~Utilities() { };

    virtual std::string ParseString(std::string const& RawString) = 0;
};

UtilitiesWin.h (用于 Windows 类/实现)

#include <string>
#include "Utilities.h"

class UtilitiesWin : public Utilities
{
public:
    UtilitiesWin() { };
    virtual ~UtilitiesWin() { };

    virtual std::string ParseString(std::string const& RawString);
};

UtilitiesWin.cpp

#include <string>
#include "UtilitiesWin.h"

std::string UtilitiesWin::ParseString(std::string const& RawString)
{
    // Magic happens here!
    // I'll put in a line of code to make it seem valid
    return "";
}

那么在我的代码的其他地方我有这个

#include <string>
#include "Utilities.h"

void SomeProgram::SomeMethod()
{
    Utilities *u = new Utilities();
    StringData = u->ParseString(StringData); // StringData defined elsewhere
}

编译器(Visual Studio 2008)在实例声明上快要死了

c:\somepath\somecode.cpp(3) : error C2259: 'Utilities' : cannot instantiate abstract class
        due to following members:
        'std::string Utilities::ParseString(const std::string &)' : is abstract
        c:\somepath\utilities.h(9) : see declaration of 'Utilities::ParseString'

所以在这种情况下我想做的是像接口一样使用抽象类(实用程序)并让它知道要转到实现的版本(UtilitiesWin )。

显然我做错了什么,但我不确定是什么。当我写这篇文章时,我突然想到,我错过的 Utilities 抽象类的 UtilitiesWin 实现之间可能存在重要的联系,但我不确定在哪里。我的意思是,以下内容有效

#include <string>
#include "UtilitiesWin.h"

void SomeProgram::SomeMethod()
{
    Utilities *u = new UtilitiesWin();
    StringData = u->ParseString(StringData); // StringData defined elsewhere
}

,但这意味着我必须稍后有条件地浏览不同版本(即 UtilitiesMac()UtilitiesLinux() 等)

。我错过这里了吗?

PREFACE: I'm relatively inexperienced in C++ so this very well could be a Day 1 n00b question.

I'm working on something whose long term goal is to be portable across multiple operating systems. I have the following files:

Utilities.h

#include <string>

class Utilities
{
public:
    Utilities() { };
    virtual ~Utilities() { };

    virtual std::string ParseString(std::string const& RawString) = 0;
};

UtilitiesWin.h (for the Windows class/implementation)

#include <string>
#include "Utilities.h"

class UtilitiesWin : public Utilities
{
public:
    UtilitiesWin() { };
    virtual ~UtilitiesWin() { };

    virtual std::string ParseString(std::string const& RawString);
};

UtilitiesWin.cpp

#include <string>
#include "UtilitiesWin.h"

std::string UtilitiesWin::ParseString(std::string const& RawString)
{
    // Magic happens here!
    // I'll put in a line of code to make it seem valid
    return "";
}

So then elsewhere in my code I have this

#include <string>
#include "Utilities.h"

void SomeProgram::SomeMethod()
{
    Utilities *u = new Utilities();
    StringData = u->ParseString(StringData); // StringData defined elsewhere
}

The compiler (Visual Studio 2008) is dying on the instance declaration

c:\somepath\somecode.cpp(3) : error C2259: 'Utilities' : cannot instantiate abstract class
        due to following members:
        'std::string Utilities::ParseString(const std::string &)' : is abstract
        c:\somepath\utilities.h(9) : see declaration of 'Utilities::ParseString'

So in this case what I'm wanting to do is use the abstract class (Utilities) like an interface and have it know to go to the implemented version (UtilitiesWin).

Obviously I'm doing something wrong but I'm not sure what. It occurs to me as I'm writing this that there's probably a crucial connection between the UtilitiesWin implementation of the Utilities abstract class that I've missed, but I'm not sure where. I mean, the following works

#include <string>
#include "UtilitiesWin.h"

void SomeProgram::SomeMethod()
{
    Utilities *u = new UtilitiesWin();
    StringData = u->ParseString(StringData); // StringData defined elsewhere
}

but it means I'd have to conditionally go through the different versions later (i.e., UtilitiesMac(), UtilitiesLinux(), etc.)

What have I missed here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

烏雲後面有陽光 2024-09-09 02:12:34
Utilities *u = new Utilities();

告诉编译器创建一个 Utilities 类的新实例; UtilitiesWin 扩展它的事实不一定是已知的,也不会影响它。可能有很多扩展 Utilities 的类,但您告诉编译器创建 Utilities 的新实例,而不是那些子类。

听起来您想使用工厂模式,即在 Utilities 中创建一个静态方法,返回指向特定实例的 Utilities*

static Utilities* Utilities::make(void) {return new UtilitiesWin();}

在某些时候,您必须实例化一个非抽象子类;此时无法指定 UtilitiesWin

Utilities *u = new Utilities();

tells the compiler to make a new instance of the Utilities class; the fact that UtilitiesWin extends it isn't necessarily known and doesn't affect it. There could be lots of classes extending Utilities, but you told the compiler to make a new instance of Utilities, not those subclasses.

It sounds like you want to use the factory pattern, which is to make a static method in Utilities that returns a Utilities* that points to a particular instance:

static Utilities* Utilities::make(void) {return new UtilitiesWin();}

At some point you're going to have to instantiate a non-abstract subclass; there's no way around specifying UtilitiesWin at that point

风苍溪 2024-09-09 02:12:34

你似乎对自己想要什么感到有点困惑;您必须在某个阶段告诉计算机要使用实用程序的哪种实现,但是根据您设定的形状,您只需要

#ifdef windows
 Utilities* u = new UtilitiesWin();
#endif
#ifdef spaceos3
 Utilities* u = new UtilitiesSpaceOS3();
#endif

在程序中使用一次,并且大多数源文件只需调用您的方法而无需知道它是什么样的 au - 我认为这就是你的目标。

You seem a bit confused as to what you want; you have to tell the computer at some stage which implementation of Utilities it is to use, but with the shape you've set out you only need to have

#ifdef windows
 Utilities* u = new UtilitiesWin();
#endif
#ifdef spaceos3
 Utilities* u = new UtilitiesSpaceOS3();
#endif

once in the program, and most of the source files can just call methods of u without knowing what kind of a u it is - which is I think what you were aiming at.

陌伤浅笑 2024-09-09 02:12:34

在 C++ 中,你不能实例化抽象类,这正是你在这里想要做的:

Utilities *u = new Utilities();

我非常不清楚为什么你想要实例化这样一个类,以及如果你可以这样做的话你会用它做什么(你可以't)。您不能将实例化用作接口 - 类定义提供了这一点。

In C++ you cannot instantiate abstract classes, which is precisely what you are trying to do here:

Utilities *u = new Utilities();

It's very unclear to me why you would want to instantiate such a class, and what you would do with it if you could do so (which you can't). You cannot use an instantiation as an interface - the class definition provides that.

我很OK 2024-09-09 02:12:34

你“说得对”,你必须实例化一个具体类型。对此有一些常见的解决方案。

是的,您必须决定在某个地方实例化哪个类。
其实现取决于此决策的标准:二进制文件是否固定?每个进程的选择都一样吗?或者它是否会针对 SomeProgram 的每个实例而改变?

在您提到的具体类之前,可能可以在编译时做出决定,类似于汤姆的建议。

其次,SomeProgram 本身不应该做出此选择。相反,类型或实例应该可以从外部进行配置。最简单的方法是将具体实例传递给 SomeProgram 的构造函数:

class SomeProgram
{
   private:
     Utilities * m_utilities;

   public:
     Someprogram(Utilities * util) : m_utilities(util) {}

}

请注意,SomeProgram 只“知道”抽象类,而不知道任何具体类。

对于延迟构建,请使用工厂。如果应按上述方式注入实用程序类,创建成本很高,但大多数时候没有必要,您可以注入一个工厂:您传递一个 < code>UtilityFactory 到该类,SomeProgram 可以使用该类按需创建所需的实例。实际的工厂实现决定了要选择的具体类。有关更多信息,请参阅工厂模式

如果这是一个常见问题,请查看控制反转 (IoC ) - 有几个库实现可以使这变得更容易。在积极的单元测试之后,它已成为一个流行词,其中必须永久地用模拟替换“真实”实现。 (不过,我仍在等待完整的 MockOS)。不过,我在实践中还没有开发过任何真正需要 suhc 库的应用程序,而且它很可能对您的问题来说太过分了。

You are "getting" it right, you have to instantiate a concrete type. There are common solutions to this.

Yes, you have to make that decision which class to instantiate somewhere.
The implementation of that depends on the criteria for this decision: is it fixed for the binary? The same choice for each process? Or does it change for every instance of SomeProgram?

Fore the concrete classes you mention, the decision can probably be made at compile time, similar to what Tom suggests.

Second, SomeProgram should not make this choice itself. Rather the type or the instance should be configurable from the outside. The most simple approach is to pass the concrete instance to the constructor of SomeProgram:

class SomeProgram
{
   private:
     Utilities * m_utilities;

   public:
     Someprogram(Utilities * util) : m_utilities(util) {}

}

Note that SomeProgramonly "knows" the abstract class, none of the concrete classes.

For delayed construction, use a factory. If the utilities class should be injected as above, is expensive to create but isn't necessary most of the time, you would inject a factory instead: you pass a UtilityFactoryto the class, which SomeProgram can use to create the required instance on demand. The actual factory implementation decides the concrete class to chose. See Factory pattern for more.

If that's a common problem, look at Inversion of Control (IoC) - there are several library implementations out there that make that easier. It has become a buzzword in the wake of agressive unit testing, where replacing "real" implementations with mocks has to happen permanently. (I'm still waiting for a complete MockOS, though). I haven't worked on any application that seriously needed suhc a library in practice, though, and it is very likely overkill for your problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文