C++设计模式:多种方式加载文件

2023-12-26

摘要:寻找通过构造函数加载不同文件的标准C++设计模式

我有一个Base具有某些功能的类将被所有派生类使用(例如Derived_A, Derived_B)。主要区别在于Derived_A and Derived_B覆盖load函数,构造函数使用它来加载数据文件(load也可以在构造函数外部显式调用)。

我由此遇到了一个意想不到的问题:load构造函数调用的函数将类视为Base类型,但是当我使用默认构造函数并调用load显式函数,则虚函数表允许预期的load要调用的函数。

这听起来像是一个经典问题,但我无法找到解决方法(我最近在用 Python 编程,我相信,由于弱类型,它总是会调用预期的函数)。

同样,我真的很想Base::load是纯虚拟/抽象的(只有派生类会被实例化);但是,这不会编译(我相信,因为编译器认为将调用纯虚函数)。

你能帮我吗?

Output:

使用构造函数加载:
基础::加载文件_A
Base::load file_B 使用构造后函数加载:
派生_A::加载文件_A
派生_B::加载文件_B

Code:

#include <iostream>
#include <string>

class Base
{
public:
  Base() {}
  Base(std::string x)
  {
    load(x);
  }
  virtual void load(std::string x)
  {
    std::cout << "\tBase::load " << x << std::endl;
  }
};

class Derived_A : public Base
{
public:
  Derived_A() {}
  Derived_A(std::string x): Base(x) {}
  void virtual load(std::string x)
  {
    std::cout << "\tDerived_A::load " << x << std::endl;
  }
};

class Derived_B : public Base
{
public:
  Derived_B() {}
  Derived_B(std::string x): Base(x) {}
  void virtual load(std::string x)
  {
    std::cout << "\tDerived_B::load " << x << std::endl;
  }
};

int main()
{
  // simpler code, but it doesn't behave as I hoped
  std::cout << "Loading w/ constructor:" << std::endl;
  Base*der_a = new Derived_A(std::string("file_A"));
  Base*der_b = new Derived_B(std::string("file_B"));

  // this is what I want to do
  std::cout << "Loading w/ function post construction:" << std::endl;
  der_a = new Derived_A;
  der_a->load( std::string("file_A") );
  der_b = new Derived_B;
  der_b->load( std::string("file_B") );
  return 0;
}

您看到的行为在 C++ 中定义良好——在这种情况下它没有用,因为当您调用时该类尚未完全构造load(std::string) from Base::Base(std::string).

有两种直接的方法:

A

您可以使用调用 load 的容器类型(也可能保留字符串)。如果您需要保留实例(例如它们可能有专门的错误信息),这可能更实用。

class Loader 
{
public:
    Loader(Base* const p, const std::string& location) : d_base(p) 
    {
        this->d_base->load(location);
    }

private:
    std::unique_ptr<Base>d_base;
private:
    Loader(const Loader&) = delete;
    Loader& operator=(const Loader&) = delete;  
};

In use:

std::cout << "Loading w/ Loader:\n";
Loader l_der_a(new Derived_A, "file_A");
Loader l_der_b(new Derived_B, "file_B");

B

您还可以使用辅助函数来处理它:

class Base {
public:
    template<typename T>
    static void Load(const std::string& x) 
    {
         T().load(x);
    }

    Base() 
    {
    }

    Base(std::string x) 
    {
         /* load(x); << see Load(const std::string&) */
    }

    virtual ~Base() 
    {
    }

    virtual void load(std::string x) = 0;
};

In use:

std::cout << "Loading w/ Base::Load<T>():\n";
Derived_A::Load<Derived_A>("file_A");
Derived_B::Load<Derived_B>("file_B");

还有其他几种方法和变体 - 这取决于最适合您的设计的方法。对于 C++,您当然有选择。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++设计模式:多种方式加载文件 的相关文章

随机推荐