简体   繁体   English

C++ 用 mutator 方法初始化 const 成员

[英]C++ initialize const member with mutator method

Suppose the following class exists (which I cannot change).假设存在以下类(我无法更改)。

class TheirClass {
 public:
  TheirClass();
  TheirClass(const TheirClass&) = delete;
  TheirClass& operator=(const TheirClass&) = delete;
  TheirClass(TheirClass&&) = delete;
  void FinishInitialization();
}

I would like to use it in my class like so.我想像这样在我的课堂上使用它。

class MyClass {
 private:
  const TheirClass their_class_;
}

If the copy and move constructors were not deleted, I could do something like this.如果复制和移动构造函数没有被删除,我可以做这样的事情。

TheirClass CreateTheirClass() {
  TheirClass their_class;
  their_class.FinishInitialization();
  return their_class;
}

MyClass::MyClass() : their_class_(CreateTheirClass()) {}

Currently my solution is to use pointers.目前我的解决方案是使用指针。

class MyClass {
 private:
  const std::unique_ptr<const TheirClass> their_class_;
}
std::unique_ptr<TheirClass> CreateTheirClass() {
  auto their_class = std::make_unique<TheirClass>();
  their_class->FinishInitialization();
  return their_class;
}

MyClass::MyClass() : their_class_(CreateTheirClass()) {}

But this seems to add unnecessary complexity and a needless performance hit (storing the object on the heap rather than the stack).但这似乎增加了不必要的复杂性和不必要的性能损失(将对象存储在堆上而不是堆栈上)。

How can I have a const TheirClass as member in my class while still being able to call TheirClass::FinishInitialization (once, upon initialization of my class)?我怎样才能在我的班级中有一个const TheirClass作为成员,同时仍然能够调用TheirClass::FinishInitialization (一次,在我的班级初始化时)?

You can make a wrapper class that calls FinishInitialization in its constructor, but only exposes the instance as a const .您可以创建一个在其构造函数中调用FinishInitialization的包装类,但仅将实例公开为const

class TheirClassWrapper final
{
public:
    /// The question didn't specify `args`, but I assume you want them here
    template <typename... Args>
    explicit TheirClassWrapper(Args&&... args)
            : impl_()
    {
        impl_.FinishInitialization(std::forward<Args>(args)...);
    }

    const TheirClass& operator*() const noexcept { return impl_; }

    const TheirClass* operator->() const noexcept { return &impl_; }

private:
    TheirClass impl_;
};

Use the wrapper instead:改用包装器:

class MyClass
{
public:
    MyClass();

    // ...

private:
    const TheirClassWrapper their_class_;
}

You then use their_class_->whatever() or *their_class_ to access things.然后您使用their_class_->whatever()*their_class_来访问事物。 It looks like a pointer, but it will get trivially inlined by your compiler.它看起来像一个指针,但它会被你的编译器简单地内联。


A potentially more generic solution to this is:一个可能更通用的解决方案是:

template <typename T>
class InitWrapper final
{
public:
    template <typename FInit>
    explicit InitWrapper(FInit&& init)
    {
        init(impl_);
    }

    const T& operator*()  const noexcept { return impl_; }
    const T* operator->() const noexcept { return impl_; }

private:
    T impl_;
};

This allows you to run some arbitrary function in the InitWrapper constructor, while still only exposing the const T view of things.这允许您在InitWrapper构造函数中运行一些任意函数,同时仍然只公开事物的const T视图。

MyClass::MyClass()
        : their_class_([](TheirClass& x) { x.FinishInitialization(); })
{ }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM