【问题标题】:Return value of virtual functions in interface接口中虚函数的返回值
【发布时间】:2015-06-01 10:48:40
【问题描述】:

一个类返回'int',其他类返回'double'。两个类的接口中方法“GiveMeTheValue”的签名是什么。 我想编译以下代码:

class Interface
{
    public:
        virtual arbitrary_type GimeMeTheValue(void) {}; 
};

class TakeInt : public Interface
{
    public:
        arbitrary_type GimeMeTheValue(void) {
            return 10;
        }
};

class TakeDouble : public Interface
{
    public:
        arbitrary_type GimeMeTheValue(void) { 
            return 3.14;
        }
};

int main()
{
    Interface * obj;

    obj = new TakeInt(); 
    cout << obj -> GimeMeTheValue() << endl; // It's 10, thank you

    obj = new TakeDouble();
    cout << obj -> GimeMeTheValue() << endl; // Oh it's 3.14, I love you c++
}

当然没有这样的“arbitary_type”。 这行得通...

class Interface
{
    public:
        virtual void * GimeMeTheValue(void) {}; 
};

class TakeInt : public Interface
{
    public:
        void * GimeMeTheValue(void) {
            int value = 10;
            int * ptr = &value;
            return ptr; 
        }
};

class TakeDouble : public Interface
{
    public:
        void * GimeMeTheValue(void) { 
            double value = 3.14;
            double * ptr = &value;
            return ptr; 
        }
};

int main()
{
    Interface * obj;

    obj = new TakeInt();
    cout << *( (int *) (obj -> GimeMeTheValue()) ) << endl;

    obj = new TakeDouble();
    cout << *( (double *) (obj -> GimeMeTheValue()) ) << endl;
}

处理“void *”相当复杂。有没有其他想法来实现一些简单的东西(比如第一个代码示例)?谢谢。

【问题讨论】:

  • 您返回指向局部变量的指针。永远不要这样做:-)。
  • virtual void * GimeMeTheValue(void) {}; 发出关于不返回值的编译器警告?这似乎variant类型的合适候选者。正如所写,这会在多个位置调用未定义的行为
  • WhozCraig,是的,未定义的行为。但是还有其他选择吗?我的所有类都需要一个(!)虚函数名称。但是每个类都返回自己的值类型。那么签名是什么?!
  • @Pleeea,它看起来是一个不错的 variant 类型的候选者;一种能够表示多种基本类型的类型,(当然,在任何给定时间只能表示一种)。
  • 在这段代码的情况下,Interface 类实际上并不是一个通用接口的好候选——派生类做不同的事情并返回不同的结果。尽管它们具有相似的签名,但它们并不相同。这是模板基类而不是具体抽象基类的候选对象。

标签: c++ interface virtual void void-pointers


【解决方案1】:

基类Interface 无法知道每个后代想要返回的不同数据类型。使用不同的返回类型违背了多态性的目的。所以我能想到的唯一方法是让GiveMeTheValue() 返回一个知道它持有什么样的值的对象类型,然后使该对象可流式处理。

enum VariantType {varNull, varInt, varDouble};

struct Variant
{
    VariantType Type;
    union {
        int intValue;
        double dblValue;
    };

    Variant() : Type(varNull) {}
    Variant(int value) : Type(varInt), intValue(value) {}
    Variant(double value) : Type(varDouble), dblValue(value) {}

    void writeTo(std::ostream &strm)
    {
        switch (Type)
        {
            case varNull:   strm << "(null)"; break;
            case varInt:    strm << intValue; break;
            case varDouble: strm << dblValue; break; 
        }
    }
};

class Interface
{
public:
    virtual ~Interface() {}
    virtual Variant GimeMeTheValue(void) = 0; 
};

class TakeInt : public Interface
{
public:
    Variant GimeMeTheValue(void)
    {
        return Variant(10);
    }
};

class TakeDouble : public Interface
{
public:
    Variant GimeMeTheValue(void)
    { 
        return Variant(3.14);
    }
};

std::ostream& operator<<(std::ostream &strm, const Variant &v)
{
    v.writeTo(strm);
    return strm;
}

int main()
{
    Interface * obj;

    obj = new TakeInt(); 
    cout << obj->GimeMeTheValue() << endl; // It's 10, thank you
    delete obj;

    obj = new TakeDouble();
    cout << obj->GimeMeTheValue() << endl; // Oh it's 3.14, I love you c++
    delete obj;
}

【讨论】:

  • >> 使用不同的返回类型违背了多态性的目的。
  • @Pleeea:是的。您想通过基类指针使用对象而不关心派生类实际上是什么,只需要所有派生类实现一致的接口。这就是多态性的本质。一个虚函数不能有不同的返回类型。它只能返回所有派生类必须遵守的 1 个不同类型。因此,要让派生类返回不同的类型,您需要一个不同的返回类型,它可以在运行时调整其行为,这就是变体所做的。
猜你喜欢
  • 1970-01-01
  • 2019-09-27
  • 2018-07-12
  • 1970-01-01
  • 1970-01-01
  • 2019-12-17
  • 1970-01-01
  • 2018-03-22
  • 2015-02-05
相关资源
最近更新 更多