我没有得到关于这个抽象类实现的内容?

时间:2010-05-17 21:53:40

标签: c++ abstract-class

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

我正致力于一些长期目标是可跨多个操作系统移植的东西。我有以下文件:

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'

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

显然我做错了什么,但我不确定是什么。在我写这篇文章的过程中,我发现在UtilitiesWin实现的Utilities抽象类之间可能存在一个重要的联系,我错过了,但我不知道在哪里。我的意思是,以下作品

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

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

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

我在这里错过了什么?

4 个答案:

答案 0 :(得分:7)

Utilities *u = new Utilities();

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

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

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

在某些时候,你将不得不实例化一个非抽象的子类;那时无法指定UtilitiesWin

答案 1 :(得分:2)

你似乎对你想要的东西感到困惑;您必须在某个阶段告诉计算机它将使用哪种实用程序,但是您已经设定的形状只需要

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

一旦进入程序,大多数源文件只能调用你的方法,而不知道它是什么类型的 - 这就是我认为你的目标。

答案 2 :(得分:2)

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

Utilities *u = new Utilities();

我很不清楚为什么你想要实例化这样一个类,如果你能这样做你会怎么做(你做不到)。您不能将实例化用作接口 - 类定义提供了。

答案 3 :(得分:2)

你正在“正确”,你必须实例化一个具体的类型。有共同的解决方案。

是的,你必须决定在哪个类实例化某个地方。
这个的实现取决于这个决定的标准:它是否为二进制文件固定?每个过程都有相同的选择吗?或者它是否会针对SomeProgram的每个实例进行更改?

在您提到的具体课程之前,可能会在编译时做出决定,类似于Tom所建议的。

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

class SomeProgram
{
   private:
     Utilities * m_utilities;

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

}

请注意SomeProgram只“知道”抽象类,没有具体的类。

对于延迟施工,请使用工厂。如果实用程序类应按上述方式注入,创建成本高昂,但大部分时间都不需要,您可以注入工厂:将UtilityFactory传递给类,SomeProgram可以使用它来按需创建所需的实例。实际的工厂实现决定了要选择的具体类。有关详情,请参阅Factory pattern

如果这是一个常见问题,请查看Inversion of Control(IoC) - 有几个库实现可以让您更轻松。它已经成为一个流行的单元测试后的流行词,用模拟取代“真正的”实现必须永久发生。 (我还在等待一个完整的MockOS)。但是,我没有在实践中对任何真正需要图书馆的应用程序进行过工作,而且很可能对你的问题有些过分。