Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在不使用RTTI的情况下(优雅地)实现这一点?_C#_C++_Polymorphism_Rtti - Fatal编程技术网

C# 如何在不使用RTTI的情况下(优雅地)实现这一点?

C# 如何在不使用RTTI的情况下(优雅地)实现这一点?,c#,c++,polymorphism,rtti,C#,C++,Polymorphism,Rtti,我是用C语言编写的,想到的最快解决方案是使用as或is关键字。我开始想知道如何在没有RTTI的情况下在C++中巧妙地实现它。。。甚至在没有上述关键字的C语言中 以下是简化的问题: 有一个class命令,它包含一个所谓的令牌流 class Command { public List<Token> Toks {get; set;} //... } 令牌当前可能是关键字或游戏对象 class Token { //nothing in here :( } cla

我是用C语言编写的,想到的最快解决方案是使用as或is关键字。我开始想知道如何在没有RTTI的情况下在C++中巧妙地实现它。。。甚至在没有上述关键字的C语言中

以下是简化的问题:

有一个class命令,它包含一个所谓的令牌流

class Command
{
    public List<Token> Toks {get; set;}

    //...
}
令牌当前可能是关键字或游戏对象

class Token
{
    //nothing in here :(
}

class KWToken : Token
{
    public List<string> Synonyms {get; set;}
}

class GOToken : Token
{

}
稍后,我将循环查看命令对象的令牌列表,并根据存储的令牌类型进行操作

这个场景中的难点是KWToken对象包含我需要的关联字符串列表

当然,如前所述,C中的简单解决方案将使用is或as关键字

我想到了一些不那么性感的方法。 有人有好主意吗

编辑

删除打印示例,因为它似乎具有误导性
KWToken对象中的同义词列表将通过关联的命令对象在许多地方访问。不是像我在示例中暗示的那样只打印一次。

这是非常经典的多态性。下面的方法不管用吗

abstract class Token
{
    public abstract void DoStuff();
}

class KeywordToken : Token
{
    List<string> Synonyms { get; set; }
    public override void DoStuff()
    {
        foreach (string s in Synonyms)
        {
            Console.WriteLine(s);
        }
    }
}

class GameObjectToken : Token
{
    public override void DoStuff()
    {
        // Do something else.
    }
}


// Elsewhere
foreach (var token in cmd.Toks)
{
    token.DoStuff();
}

这是非常经典的多态性。下面的方法不管用吗

abstract class Token
{
    public abstract void DoStuff();
}

class KeywordToken : Token
{
    List<string> Synonyms { get; set; }
    public override void DoStuff()
    {
        foreach (string s in Synonyms)
        {
            Console.WriteLine(s);
        }
    }
}

class GameObjectToken : Token
{
    public override void DoStuff()
    {
        // Do something else.
    }
}


// Elsewhere
foreach (var token in cmd.Toks)
{
    token.DoStuff();
}

您也可以尝试使用。尽管对于您的简单场景来说,这可能有些过分。

您也可以尝试使用。虽然对于您的简单场景来说,这可能有些过分。

如果您不想使用RTTI,如果可能的话,我建议您使用它,您可以自己实现它

#include <string>

template <class T>
class List
{};

class Token
{
    //nothing in here :(
public:
        enum TokenType
        {
                KWToken,
                GOToken
        };

        virtual TokenType Which() = 0;
};

class KWToken : public Token
{
public:
    List<std::string> Synonyms() {
        //get
        return List<std::string>();
    }
    void Synonyms(List<std::string>& value) {
        //set
    }
    virtual TokenType Which() {return Token::KWToken; }
};

class GOToken : public Token
{
        virtual TokenType Which() {return Token::GOToken; }

};

int main() {
  Token* T = GetToken();
  switch(T->What()) {
  case Token::KWToken:
     //Do fancy stuff
     static_cast<KWToken*>(T)->Synonyms();
     break;
  }
}

如果您不想使用RTTI,如果可能的话,我建议您使用它,您可以自己实现它

#include <string>

template <class T>
class List
{};

class Token
{
    //nothing in here :(
public:
        enum TokenType
        {
                KWToken,
                GOToken
        };

        virtual TokenType Which() = 0;
};

class KWToken : public Token
{
public:
    List<std::string> Synonyms() {
        //get
        return List<std::string>();
    }
    void Synonyms(List<std::string>& value) {
        //set
    }
    virtual TokenType Which() {return Token::KWToken; }
};

class GOToken : public Token
{
        virtual TokenType Which() {return Token::GOToken; }

};

int main() {
  Token* T = GetToken();
  switch(T->What()) {
  case Token::KWToken:
     //Do fancy stuff
     static_cast<KWToken*>(T)->Synonyms();
     break;
  }
}

微软的COM架构优雅地处理了这个问题。基类IUnknown只包含获取接口所需的最低功能,接口定义对象可以做什么或不能做什么。在您的例子中,您可以定义关键字列表的接口,如果该接口返回NULL,则对象不支持关键字列表。您不需要实现COM本身,我只是以它为例


您可以根据对象的功能来定义对象,而不是根据对象是什么来定义对象。

Microsoft的COM体系结构很好地处理了这一问题。基类IUnknown只包含获取接口所需的最低功能,接口定义对象可以做什么或不能做什么。在您的例子中,您可以定义关键字列表的接口,如果该接口返回NULL,则对象不支持关键字列表。您不需要实现COM本身,我只是以它为例


您可以根据对象的功能而不是对象的类型来定义对象。

使用LINQ的OfType仅提取列表中所需类型的元素:

foreach(var kw in command.Toks.OfType<KWToken>())
{
  kw.Synonyms[...];
}

使用LINQ的OfType仅提取列表中所需类型的元素:

foreach(var kw in command.Toks.OfType<KWToken>())
{
  kw.Synonyms[...];
}

正如其他人所建议的,多态性和访问者模式似乎很适合这个问题

<>在C++中,也可以使用Boosi::Value.< /P>之类的类来进行一般性的操作。 然后可以大致如下定义您的命令类:

class Command
{
public:
    std::vector<boost::variant<KWToken, GOToken> > Toks;

    //...
};
boost::apply_visitor( my_visitor(), v );
有关详细信息,请参阅

这避免了传统的OOP多态性,为您提供了使用静态多态性的完全基于模板的解决方案

在这种方法中,您甚至不需要公共令牌基类,具体的令牌类型也不需要实现任何虚拟函数


在C语言中,您实际上没有这个选项,仍然是正确解决方案的访问者模式必须使用动态多态性来实现。

正如其他人所建议的,多态性和访问者模式似乎很适合这个问题

<>在C++中,也可以使用Boosi::Value.< /P>之类的类来进行一般性的操作。 然后可以大致如下定义您的命令类:

class Command
{
public:
    std::vector<boost::variant<KWToken, GOToken> > Toks;

    //...
};
boost::apply_visitor( my_visitor(), v );
有关详细信息,请参阅

这避免了传统的OOP多态性,为您提供了使用静态多态性的完全基于模板的解决方案

在这种方法中,您甚至不需要公共令牌基类,具体的令牌类型也不需要实现任何虚拟函数


在C语言中,您实际上没有这个选项,仍然是正确解决方案的访问者模式必须使用动态多态性来实现。

我对您的场景了解得不够,但它可能是添加方法的一个选项

virtual bool hasSynonyms() = 0;
virtual List<std::string> getSynomyms() { return List<std::string>; /*empty list */ }
到您的令牌基类


只有在可能有其他标记具有同义词的情况下,我才会这样做,否则访问者模式才是正确的选择。

我对您的场景了解不够,但这可能是添加方法的一个选项

virtual bool hasSynonyms() = 0;
virtual List<std::string> getSynomyms() { return List<std::string>; /*empty list */ }
到您的令牌基类


我只会在可能有其他同义词的代词的情况下这样做,否则访问者模式就是最好的选择。

啊,废话。我知道我不应该添加那个打印示例。请看,同义词列表必须在许多地方访问

锿。不只是为了打印。所以,只需添加多个抽象方法。您说我想循环一个命令对象的令牌列表,并根据存储的令牌类型进行操作。这正是通过抽象方法实现多态性的目的:根据对象的类型做一些不同的事情。我知道我不应该添加那个打印示例。请看,同义词列表必须在许多地方访问。不只是为了打印。所以,只需添加多个抽象方法。您说我想循环一个命令对象的令牌列表,并根据存储的令牌类型进行操作。这正是通过抽象方法实现多态性的目的:根据对象的类型做一些不同的事情。但是你仍然需要使用动态施法,对吗?@rao no然后你可以简单地调用What method->查看编辑过的答案我的意思是如果在你的示例中t应该是指向KWToken的指针,如何访问同义词成员?@rao您可以使用static_cast-这在不使用RTTI的情况下有效,因为您知道指针的显式类型。@rao或c风格的cast运算符也想到了类似的方法。但是你仍然需要使用动态施法,对吗?@rao no然后你可以简单地调用What method->查看编辑过的答案我的意思是如果在你的示例中t应该是指向KWToken的指针,如何访问同义词成员?@rao您可以使用static_cast-这在不使用RTTI的情况下有效,因为您知道指针的显式类型。@rao或c-style cast运算符只是为了澄清一点,您是否正在寻找一种干净的语言无关解决方案,该解决方案可以在两种语言中工作,当然需要进行适当的修改,或者是基于C++模板的解决方案,例如,基于C LINQ的解决方案也有相关的吗?是的,我的意思是语言不可知的解决方案,不使用任何语言提供的RTI能力。但我还是对后者感到好奇。啊,真遗憾。我猜我的答案是不那么相关的,因为它是相当C++特定的。一点也不!我花了大约45分钟阅读访客模式和与boost相关的解决方案。乍一看,这似乎是一种性感的做事方式。然后我去看了一些蝙蝠侠。很清楚,你是在寻找一种干净的语言不可知的解决方案,它可以在两种语言中进行适当的修改,或者是特定于C++模板的解决方案,例如,或者基于C LINQ的解决方案也同样适用?我的意思是语言不可知的解决方案——不使用任何语言提供的RTTI功能。但我还是对后者感到好奇。啊,真遗憾。我猜我的答案是不那么相关的,因为它是相当C++特定的。一点也不!我花了大约45分钟阅读访客模式和与boost相关的解决方案。乍一看,这似乎是一种性感的做事方式。然后我去看了一些蝙蝠侠。我认为这将被视为RTTI的使用。我认为这将被视为RTTI的使用。我在设计模式知识方面有点落后,但我从昨天开始就花时间阅读了这个模式,似乎这是正确和最优雅的解决方案。当然,正如你所说,对于这种小情况来说,这是过分的。谢天谢地!我在设计模式知识方面有点落后,但从昨天开始我就花时间阅读了这个模式,看起来这是正确的、最优雅的解决方案。当然,正如你所说,对于这种小情况来说,这是过分的。谢天谢地+1:在这种情况下,访问者模式似乎是可行的,尽管我目前的问题是一个小场景,可以通过RTTI解决。感谢面向boost的解决方案。+1:在这种情况下,访问者模式似乎是可行的,尽管我目前的问题只是一个小问题,可以通过RTTI解决。感谢面向boost的解决方案。不,只有一个令牌派生类型具有同义词。不,只有一个令牌派生类型具有同义词。