Подтвердить что ты не робот

Правильный способ инициализации структуры в конструкторе класса

Поэтому я хочу добавить структуру из файла заголовка c как члена класса в класс С++. Но я получаю ошибку компилятора для файла cpp: bar was not declared inn this scope. Это то, что у меня есть:

//    myClass.hpp
#include fileWithStruct.h

class myClass
{
    public:
        struct foo bar;
};


//myClass.cpp

#include "myClass.hpp"

//Initialize structure in Constrcutor
myClass::myClass(  )
{
    bar = {1, 0, "someString", 0x4};
}
4b9b3361

Ответ 1

Стиль С++ 03

#include "fileWithStruct.h"
/* say the contents were
struct foo
{
   int foo1;
   float foo2;
};
*/

class myClass
{
    public:
        int val;
        foo bar;
        // since foo is a POD-struct (a.k.a C struct), no constructor would be present
        // however bar() will zero-initialize everything in the struct
        myClass() : val(), bar()
        {
        }
};

круглые скобки, следующие за bar, имеют значение. Обратите внимание на значение и нуль-инициализацию, чтобы понять, почему это работает. Следует отметить, что добавив конструктор к myClass, мы сделали его не-POD-типом. Чтобы обойти это, можно сохранить myClass как совокупность и написать:

class myClass
{
    public:
        int val;
        foo bar;
};

int main()
{
   myClass zeroed_obj = { };
   myClass inited_obj = { 2, {0, 1.0f} };
   myClass partially_inited_obj = { 2 };    // equivalent to {2, {}}; which would zero all of myClass::bar
   myClass garbage_obj;    // warning: when left uninitialized, every member without a constructor will end up with garbage value
}

Стиль С++ 11

class myClass
{
public:
   // default member initializations
   int val = { };         // zero-initialization
   foo bar = { 0, 0.0f }; // aggregate-initializing foo here, just giving { } will zero all of myClass::bar

   // should you want to receive an element from the constructor, this can be done too
   // aggregate initializing a struct in constructor initialization list is allowed from C++11 onwards
   // in C++03, we would've resorted to just setting the member of bar inside the constructor body
   myClass(int _foo1) : bar{_foo1, 0.f}, val{}
   {
   }

   // since we've a non-default constructor, we've to re-introduce the default constructor
   // if we need the above in-class initialization to work
   myClass() = default;
};

Здесь мы используем синтаксис синтаксиса синтаксиса С++ 11 . Однако, делая это, myClass становится не-POD-типом; член инициализации сродни добавлению конструктора в класс, тем самым предоставляя myClass нетривиальный, но стандартный класс макета. Согласно С++ 11 для класса POD он должен быть как тривиальным, так и стандартным макетом. Вместо этого

#include "fileWithStruct.h"
#include <type_traits>
#include <iostream>

class myClass
{
public:
   int val;
   foo bar;
};

int main()
{
    myClass obj { }; // initializes val, bar.foo1 and bar.foo2 to 0
    myClass m { 0, {1, 2.0f} }; // initilizes each member separately
    std::cout << std::is_pod<myClass>::value << std::endl; // will return 1
}

сохранит myClass как POD.

Обратитесь к этому превосходному сообщению, чтобы узнать больше об агрегатах и ​​POD.

Ответ 2

То, что вы делаете, это назначение, а не инициализация. Инициализация происходит в списке инициализации конструктора, перед телом конструктора или в С++ 11 в инициализаторе сразу после объявления переменной-члена:

myClass.hpp, общий случай:

/** you might want to do this if you are linking 
 * against the C lib or object file of that header:
 */
extern "C" { 
  #include fileWithStruct.h
}

class myClass
{
public:
  foo bar; //no need for "struct" in C++ here
};

С++ 11:

myClass.cpp

#include "myClass.hpp"

//Initialize structure in Constrcutor
myClass::myClass(  )
  : bar{1, 0, "someString", 0x4}
{}

Функция Antoher заключается в том, чтобы обеспечить начальное значение foo с помощью атрибута brace-or-equal-initializer в объявлении переменной-члена:

myClass.hpp

extern "C" { 
  #include fileWithStruct.h
}

class myClass
{
public:
  foo bar{1, 0, "someString", 0x4};
};

В этом случае вам не нужно определять конструктор, поскольку он неявно генерируется компилятором (при необходимости), правильно инициализируя bar.

С++ 03:

Здесь агрегатная инициализация в списках инициализации недоступна, поэтому вам придется использовать обходные методы, например:

myClass.cpp

#include "myClass.hpp"

//Initialize structure in Constrcutor
myClass::myClass(  )
  : bar() //initialization with 0
{
  const static foo barInit = {1, 0, "someString", 0x4}; //assignment
  bar = barInit;
}

Или:

#include "myClass.hpp"
namespace {
  foo const& initFoo() {
    const static foo f = {1, 0, "someString", 0x4};
    return f;
  }
}

//Initialize structure in Constrcutor
myClass::myClass(  )
  : bar(initFoo()) //initialization
{ }

Ответ 3

Инициализация должна быть выполнена таким образом (С++ 11):

myClass::myClass(  )
: bar{1, 0, "someString", 0x4}
{

}

Кроме того, не забудьте объявить свой конструктор в определении вашего класса.

Ответ 4

Вам нужно указать, что структура foo должна иметь "C-linkage". Ниже приведен полный пример.

// fileWithStruct.h
#ifdef __cplusplus
extern "C" { // Declare as extern "C" if used from C++
#endif

typedef struct _foo
{
  int a;
  int b;
  const char* c;
  int d;
} foo;


#ifdef __cplusplus
}
#endif

Заголовочный файл myClass:

// myClass.hpp
#include "fileWithStruct.h"

class myClass
{
public:
  myClass();

  foo bar;
};

Реализация С++ 11 myClass, которая использует расширенные списки инициализаторов:

// myClass.cpp
#include "myClass.hpp"

myClass::myClass(  )
  : bar({1, 0, "someString", 0x4})
{
}

... и версию С++ 03, если вы еще не переместились на С++ 11:

#include "myClass.hpp"

myClass::myClass(  )
  : bar()
{
  bar.a = 1;
  bar.b = 0;
  bar.c = "someString";
  bar.d = 0x4;
}