【问题标题】:C++ return different objectsC++ 返回不同的对象
【发布时间】:2018-06-22 13:21:19
【问题描述】:

我有一个大问题。我不会通过包装类选择存储服务。返回值必须是存储服务类中的对象。我粘贴了我目前的方法。但到目前为止我的心态并没有奏效。

错误:

错误:自动返回类型推导不一致:'SQL*' 然后'REDIS*' return new REDIS();

最大的愿望是有一个定义结构的接口类和一些包含目标存储服务所有必要操作的“驱动程序类”。

我希望你有另一种方法,我该如何解决这个问题..

    #include <iostream>


class StorageTemplate {
    public:
        virtual bool UserhasSurName() = 0;
        virtual bool UserhasGivenName() = 0;
};

class SQL: public StorageTemplate {
    public:
        bool UserhasSurName() {
            //A SQL QUERY
            return true;
        }
        bool UserhasGivenName() {
            //AN ANOTHER SQL QUERY
            return true;
        }
};

class REDIS: public StorageTemplate {
    public:
        bool UserhasSurName() {
            //A REDIS CALL
            return false;
        }
        bool UserhasGivenName() {
            //A REDIS CALL
            return false;
        }
};


class controller {
    public:
        auto test(int select) {
            if( select == 1)
            {
                return new SQL(); 
            } else {
                return new REDIS();
            }
        }
};



int main(int argc, char const *argv[])
{
    controller cont;
    auto schnitzel = cont.test(1);
    auto mitzel = cont.test(2);
    std::cout << schnitzel->UserhasSurName() << std::endl;
    std::cout << mitzel->UserhasSurName() << std::endl;
}

【问题讨论】:

  • 1) “但我的心态到目前为止还没有奏效。” 这样的说法是没有用的。怎么样,没用? 2)请提供minimal reproducible examplehallo是什么?)。
  • 哦,对不起,这个功能已被弃用,我的意思是 UserhasSurName() -.-
  • 标识符全部使用大写并不是一个好主意。
  • 谢谢。但这不是问题...
  • auto 不能从两个派生中推断出基类指针,明确地这样做,错误很明显

标签: c++ database oop auto


【解决方案1】:

您面临的问题如下:考虑您的功能

auto test(int select) {
    if (select == 1) {
        return new SQL(); 
    } else {
        return new REDIS();
    }
}

如果您尝试评估 test(1),则会扩展为

auto test(int select) {
    if (true) {
        return new SQL(); 
    } else {
        return new REDIS();
    }
}

导致类型错误!

我向您展示了解决您的问题的三种解决方法:

1.函数模板和if constexpr

test 设为函数模板并使用C++17 功能if constexpr 检查正确的类型:

template<typename T>
auto test() {
    if constexpr(std::is_same<T, SQL>::value) {
        return new SQL();
    } else {
        return new REDIS();
    }
}

像这样在main() 中使用它:

int main(){
    controller cont;
    auto schnitzel = cont.test<SQL>();
    auto mitzel = cont.test<REDIS>();
    std::cout << schnitzel->UserhasSurName() << std::endl;
    std::cout << mitzel->UserhasSurName() << std::endl;
}

2。函数模板和 std::unique_ptr

如果您想避免使用if constexpr,您可以简单地返回std::unique_ptr 的实例而不是原始指针。这是首选的方法:

template<typename T>
auto test() {
    return std::unique_ptr<T>(new T);
}

或者,您也可以返回 std::make_unique&lt;T&gt;()

3.返回基类的实例

这是避免类型错误的最明显的解决方案:只需返回基类的实例。如上所述,这里首选使用智能指针的解决方案:

std::unique_ptr<StorageTemplate> test(const int select) {
    if (select == 1) {
        return std::make_unique<SQL>();
    } else {
        return std::make_unique<REDIS>();
    }
}

如果你真的想避免使用智能指针,只需使用这样的原始指针:

StorageTemplate* test(const int select) {
    if (select == 1) {
        return new SQL();
    } else {
        return new REDIS();
    }
}

【讨论】:

  • _StorageTemplate - 这是非法的
  • @datell 哇,非常感谢!但是当我运行 3.(使用 unique_ptr)时,我收到错误“解析失败”
  • @N.Men 请使用-std=c++14编译
  • @Slava 你是什么意思?
  • 此类标识符已保留,不能在用户代码stackoverflow.com/questions/228783/…中使用
【解决方案2】:

在这段代码中

auto test(int select) {
    if( select == 1)
    {
        return new SQL(); 
    } else {
        return new REDIS();
    }

auto 无法推断,因为它只匹配精确类型。所以即使SQLREDIS继承自StorageTemplateStorageTemplate也不会被推导出来。你需要指定类型

StorageTemplate* test(int select) {
    if( select == 1)
    {
        return new SQL(); 
    } else {
        return new REDIS();
    }

【讨论】:

  • 这里你真的应该使用智能指针,否则你必须记住在调用站点完成后删除指针。
  • @NathanOliver 我完全同意,但我尝试尽可能少地更改 OP 的代码
  • 另外,他可以将每个新对象静态转换为 StorageTemplate*,但那么自动的意义何在..
  • 是的,但是 OPs 代码有内存泄漏,你应该在你的回答中提到这一点
  • 谢谢!!是的,我知道智能指针比原始 c 指针更好。
【解决方案3】:

在 test() 中返回错误 Auto,它返回两种不同的类型。更改为StorageTemplate*

class controller {
    public:
        StorageTemplate* test(int select) {
            if( select == 1)
            {
                return new SQL(); 
            } else {
                return new REDIS();
            }
        }
};

【讨论】:

  • 谢谢!!但我遇到了一个新错误。请参阅我在更新 2 下的帖子
  • 请看我的帖子“UPDATE 2”下面的错误信息很短!
猜你喜欢
  • 2016-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-06
  • 1970-01-01
  • 2015-09-11
  • 2013-02-21
  • 1970-01-01
相关资源
最近更新 更多