【问题标题】:Is there a way I can swap out member variables without passing them individually in a child constructor?有没有一种方法可以交换成员变量,而无需在子构造函数中单独传递它们?
【发布时间】:2019-07-26 21:55:29
【问题描述】:

我的课程如下:

class Base
{
    public:
        virtual int ReturnX()
        {
            return x;
        }

    private:
        int x = 5;
};

class Derived : public Base
{
    private:
        int x = 10;
};

代码如下:

int main()
{
    std::unique_ptr<Base> b = std::make_unique<Derived>();

    std::cout << b->ReturnX() << std::endl;
}

我知道如果我在Derived 中覆盖ReturnX,那么基指针将正确使用正确的ReturnX,但我如何让它使用正确的x 值?我希望线路返回 10。

我不想只在构造函数中传递它的原因是我有许多 (10+) 多维 std::arraysx 并且将它们单独传递给构造函数非常乏味。

【问题讨论】:

  • 程序的行为是不确定的,因为唯一指针通过基指针销毁对象,而基类的析构函数是非虚的。
  • 展示一个“乏味”程序示例,以便我们了解您要解决的问题。
  • 如果要访问Derived的x,需要重写ReturnX函数并指定。
  • @John 如果功能相同,有没有办法使用'using'重新定义它而不复制和粘贴代码?
  • 这样不行。子类继承了这个函数,但是如果你想让它做别的事情,那么你需要重写这个函数并告诉它要做什么。

标签: c++ class virtual


【解决方案1】:

方案一:根据派生类提供的策略构造基类成员

这里,基类由基类提供策略。该策略基本上只包含返回成员初始值的函数。

class Base {
    int x;
    std::string y;
   public:
    struct DefaultPolicy {
        int getX() { 
            return 5;
        }
        std::string getY() {
            return "Hello"; 
        }
    }; 
    
    virtual int getX() {
        return x;
    }
    virtual std::string getY() {
        return y;
    }

    template<class Policy>
    Base(Policy&& p) 
      : x(p.getX())
      , y(p.getY())
    {}

    // By default, Base uses the DefaultPolicy
    Base() : Base(DefaultPolicy()) {}

    virtual~Base() = default; 
};

现在,我们可以编写一个使用给定策略的派生类:

class Derived : public Base {
    // This is our policy
    struct Policy {
        int getX() {
            return 10; 
        }
        std::string getY() {
            return "Hello, world!"; 
        }
    };

   public:
    Derived() : Base(Policy()) {}
};

解决方案 2:使 base 成为可通过虚函数访问成员的接口

这里,Base 是一个没有成员变量的抽象类:

class Base {
   protected:
    virtual int& x_() = 0; 
   public:
    virtual int getX() {
        return x_();
    }

    virtual ~Base() = default; 
};

然后,我们可以根据初始值和其他东西创建单独的派生类:

class Derived1 : Base {
    int x = 5;
   protected:
    int& x_() override {
        return x;
    }
};
class Derived2 : Base {
    int x = 10;
   protected:
    int& x_() override {
        return x;
    }
};

解决方案 3:使用默认构造函数参数

有可能做这样的事情吗?

class Base {
   protected:
    int x;
   public:    
    Base(int x_ = 5) : x(x_) {}

    virtual int getX() {
        return x;
    }
    virtual ~Base() = default; 
};

class Derived : public Base {
   public:
    Derived(int x_ = 10) : Base(x_) {}
};

使用它时,创建Derived时不必为x指定值,它按预期工作:

int main() {
    std::unique_ptr<Base> b = std::make_unique<Derived>();

    // Prints 10
    std::cout << b->getX() << '\n';
}

【讨论】:

  • 您正在覆盖基类中 x 的值,但他想要的是在继承类中拥有一个可在基类中访问的成员,这是不可能的。
  • 我特别不想将值传递给构造函数,因为有很多 std::array<:array>, 10> 看起来非常难看。
  • 我提供了另外两个解决方案。解决方案 1,策略一,是最常见的情况,希望能解决您的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-25
  • 2020-11-19
相关资源
最近更新 更多