c++ - 具有抽象基类的工厂模式 - 通过 ref 或通过值返回?范围界定和切片的问题

标签 c++ pass-by-reference factory-pattern object-slicing

我有一个类似于下面代码示例的类型层次结构,我正在尝试通过工厂模式(或者,为了迂腐,而不是构建器模式,因为我的工厂从 XML 文档获取输入)来实例化它们。 .但我离题了)。

但是我尝试这样做,我遇到了一些问题,我怀疑这些问题是由于切片(如果我按值返回)或范围界定(如果我按引用返回)引起的。

例如,下面的程序在 a.doA() 行出现段错误里面C::doStuff() .如果我将调用更改为 value_C_factory<C>()ref_C_factory<C>()相反,我收到了一些关于“返回对临时文件的引用”的警告,但程序编译时出现段错误 b.doB()在下一行(没有打印任何来自 a.doA() ... 的内容)。

来自 gdb 的回溯看起来像这样——第二行是我上面提到的代码中的那行

#0  0x00007ffff7dbddb0 in vtable for std::ctype<char> () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
#1  0x00000000004010e9 in C::doStuff (this=0x7fffffffdd00) at syntax.cpp:57
#2  0x0000000000400cf2 in main () at syntax.cpp:95

是什么导致了这些段错误?正如我所怀疑的那样,它是否在值(value)/引用案例中进行切片/范围界定?如果不是,那是什么?最重要的是,从输入数据构建实例的好方法是什么?

代码示例

下面的代码应该编译并给出上面的行为,例如GCC 4.8,使用
gcc -g -Wall -std=c++11 -o test test.cpp (无论如何,这就是我所做的)。

#include <iostream>
#include <typeinfo>

class IA {
public:
    virtual void doA() const = 0;
    virtual ~IA() { }
};

class A : public IA {
private:
    std::string atask;
public:
    explicit A(const std::string &task) : atask(task) {
        std::cout << "Created A with task " << atask << std::endl;
    }

    void doA() const {
        std::cout << "I did A! " << atask << std::endl;
    }
};

class IB {
public:
    virtual void doB() const = 0;
    virtual ~IB() { }
};

class B : public IB {
private:
    std::string btask;
public:
    explicit B(const std::string &task) : btask(task) {
        std::cout << "Created B with task " << btask << std::endl;
    }

    void doB() const {
        std::cout << "I did B! " << btask << std::endl;
    }
};

class IC {
public:
    void doStuff() const;
    virtual ~IC() { }
};

class C : public IC {
private:
    const IA &a;
    const IB &b;

public:
    C(const IA &a, const IB &b) : a(a), b(b) { }

    void doStuff() const {
        a.doA();    // with value factory method, segfault here
        b.doB();    // with reference factory, segfault here instead
    }
};

template<typename TA>
TA value_A_factory() {
    return TA("a value");
}

template<typename TB>
TB value_B_factory() {
    return TB("b value");
}

template<typename TC>
TC value_C_factory() {
    return TC(value_A_factory<A>(), value_B_factory<B>());
}


template<typename TA>
const TA &ref_A_factory() {
    return TA("a ref");
}

template<typename TB>
const TB &ref_B_factory() {
    return TB("b ref");
}

template<typename TC>
const TC &ref_C_factory() {
    const TC &c(ref_A_factory<A>(), ref_B_factory<B>());
    return c;
}

int main() {
    C c = value_C_factory<C>();
    std::cout << typeid(c).name() << std::endl;
    c.doStuff();
}

最佳答案

你有两个问题,都是由未定义的行为引起的。

首先是您不能返回对局部变量的引用。一旦函数返回并且局部变量超出范围并被破坏,返回的引用又引用了什么?

另一个问题是您存储对临时值的引用。当你创建你的 CTC(value_A_factory<A>(), value_B_factory<B>()) value_X_factory 返回的值函数是临时的,一旦完成完整的表达式 (TC(...)) 就会被销毁。

关于c++ - 具有抽象基类的工厂模式 - 通过 ref 或通过值返回?范围界定和切片的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22808879/

相关文章:

c++ - 模板类和运算符重载

c - GDB: "warning: Range for type <error type> has invalid bounds"

c++ - 使用 CComObjects 的工厂模式

ruby-on-rails - Rails - 强制模型通过工厂方法创建

c++ - int vs const int&

c++ - 如何在 C++ 中设计错误代码?

c++ - 向下转换 dynamic_cast 和多态类不起作用

模板显式特化的 C++ 措辞

python - 通过迭代列表中的多个元素来构建输出字符串的正确方法是什么?

javascript - 是否可以使用 2 个工厂函数来填充 1 个实例?