c++ 避免调用成员变量的构造函数

swvgeqrz  于 2023-06-25  发布在  其他
关注(0)|答案(9)|浏览(168)

下面是一个C++类:

  1. // Header-File
  2. class A
  3. {
  4. public:
  5. A();
  6. private:
  7. B m_B;
  8. C m_C;
  9. };
  10. // cpp-File
  11. A::A()
  12. : m_B(1)
  13. {
  14. m_B.doSomething();
  15. m_B.doMore();
  16. m_C = C(m_B.getSomeValue());
  17. }

我现在想避免class A调用C m_Cany构造函数。因为在A::A()的最后一行,我无论如何都要自己初始化m_C,因为我需要首先准备m_B。我可以为class B提供一个空的默认构造函数。但这不是重点。
我已经尝试将m_C(NULL)添加到A::A()的初始化列表中。有时它工作,有时它说没有构造函数将NULL作为参数。
那么,如何让m_C保持未初始化状态呢?我知道使用指针时,m_C(NULL)方式可以工作。我不想使用new动态分配它。
任何想法都是赞赏的。

dy1byipe

dy1byipe1#

如何使用本QA中描述的技术?
Prevent calls to default constructor for an array inside class

  1. std::aligned_storage<sizeof(T[n]), alignof(T)>::type

或者,您也可以考虑使用union。AFAIK,unions will be initialized only with first named member's constructor.
比如说

  1. union
  2. {
  3. uint8_t _nothing = 0;
  4. C c;
  5. };

根据QA中提到的标准,c将被零初始化,并且其构造函数不会被调用。

ovfsdjhp

ovfsdjhp2#

你不能
当进入construcotr代码块时,所有成员变量都被完全构造。这意味着必须调用这些构造函数。
但是你可以绕过这个限制。

  1. // Header-File
  2. class A
  3. {
  4. struct Initer
  5. {
  6. Initer(B& b)
  7. : m_b(b)
  8. {
  9. m_b.doSomething();
  10. m_b.doMore();
  11. }
  12. operator int() // assuming getSomeValue() returns int.
  13. {
  14. return m_b.getSomeValue();
  15. }
  16. B& m_b;
  17. };
  18. public:
  19. A();
  20. private: // order important.
  21. B m_B;
  22. C m_C;
  23. };
  24. // cpp-File
  25. A::A()
  26. : m_B(1)
  27. , m_C(Initer(m_B))
  28. {
  29. }
展开查看全部
u5i3ibmn

u5i3ibmn3#

我看不出有什么好办法能达到你的目的。这必须是一个解决方法:

  1. // Header-File
  2. class A
  3. {
  4. public:
  5. A();
  6. private:
  7. B m_B;
  8. C m_C;
  9. static int prepareC(B& b);
  10. };
  11. // cpp-File
  12. A::A()
  13. : m_B(1)
  14. , m_C(prepareC(m_B))
  15. {
  16. }
  17. int A::prepareC(B& b)
  18. {
  19. b.doSomething();
  20. b.doMore();
  21. return b.getSomeValue();
  22. }

请确保m_B.doSomething()m_B.doMore()m_B.getSomeValue()不接触m_C(直接或间接)。
正如@Tobias正确提到的,这个解决方案取决于初始化的顺序。您需要确保m_Bm_C的定义按此顺序。
根据@Loki的想法更新了代码。

展开查看全部
jgzswidk

jgzswidk4#

你所要求的是被禁止的--这是正确的。这样可以确保每个成员都被正确初始化。不要试图绕过它-试着构建你的类,让它们与它一起工作。
想法:

  • C有一个什么都不做的构造函数
  • C有一个初始化方法,使类可用
  • C跟踪它是否被正确初始化,如果没有初始化就使用它,它会返回相应的错误。
jjhzyzn0

jjhzyzn05#

只需使用逗号表达式:

  1. A::A()
  2. : m_B(1)
  3. , m_c((m_B.doSomething(), m_B.doMore(), m_B.getSomeValue()))
  4. {
  5. }

显然,正如其他人所解释的那样,m_B最好在m_C之前声明,否则m_B.doSomething()会调用未定义的行为。

bqucvtff

bqucvtff6#

指针听起来像是唯一干净的解决方案。我看到的唯一其他解决方案是为C设置一个默认的构造函数,它什么也不做,并在C中设置一个初始化方法,稍后您自己调用。
int n.getSomeValue();

1mrurvl1

1mrurvl17#

最简单的是存储指向BC的指针。这些可以初始化为0,省略任何构造。注意不要在A的析构函数中取消引用空指针并将其删除(或使用std::unique_ptr/boost::scoped_ptr)。
但是为什么不先初始化m_B(通过适当的构造函数调用,而不是在A::A()中),然后使用初始化的B示例来初始化m_C呢?这将要求一个小的重写,但我打赌这将是值得的代码清理。

zi8p0yeb

zi8p0yeb8#

如果出于代码混乱/异常安全的原因,不想使用new动态分配它,可以使用std::unique_ptrstd::auto_ptr来解决这个问题。
避免new的一个解决方案是编辑C,使其具有两步初始化过程。然后,构造函数将构造一个“僵尸”对象,您必须在该m_C示例上调用Initialize方法来完成初始化。这与您发现的现有情况类似,您可以将NULL传递给构造函数,然后返回初始化对象。

编辑:

我之前就想到了这个(尽管它看起来很像其他人的解决方案)。但我必须得到一些确认,这不会打破之前,我添加了这个解决方案- C++可以是相当棘手的,我不经常使用它:)
这比我的其他建议更简洁,并且不需要你去搞砸除了A之外的任何实现。
简单地使用静态方法作为初始化的中间人:

  1. class A
  2. {
  3. public:
  4. A();
  5. private:
  6. static int InitFromB(B& b)
  7. {
  8. b.doSomething();
  9. b.doMore();
  10. return b.getSomeValue();
  11. }
  12. // m_B must be initialized before m_C
  13. B m_B;
  14. C m_C;
  15. };
  16. A::A()
  17. : m_B(1)
  18. , m_C(InitFromB(m_B))
  19. {
  20. }

请注意,这意味着您根本不能允许m_B依赖于AC的示例,而这个答案顶部的解决方案可能允许您将Am_C传递到m_B的方法中。

展开查看全部
6qfn3psc

6qfn3psc9#

这里我们有构建块:

  1. #include <iostream>
  2. class C
  3. {
  4. public:
  5. C(int i){std::cout << "C::C(" << i << ")" << std::endl;}
  6. };
  7. class B
  8. {
  9. public:
  10. B(int i){std::cout << "B::B(" << i << ")" << std::endl;}
  11. void doSomething(){std::cout << "B::doSomething()" << std::endl;}
  12. void doMore(){std::cout << "B::doMore()" << std::endl;}
  13. int getSomeValue(){return 42;}
  14. };

如果你想为B创建一个新的构造,可以考虑创建一个派生类:

  1. class B1 : public B
  2. {
  3. public:
  4. B1() : B(1)
  5. {
  6. doSomething();
  7. doMore();
  8. }
  9. };

现在使用从B派生的类B1:

  1. class A
  2. {
  3. private:
  4. B1 _b;
  5. C _c;
  6. public:
  7. A() : _c(_b.getSomeValue()){std::cout << "A::A()" << std::endl;}
  8. };

然后:

  1. int main()
  2. {
  3. A a;
  4. }

输出:

  1. B::B(1)
  2. B::doSomething()
  3. B::doMore()
  4. C::C(42)
  5. A::A()
展开查看全部

相关问题