내부적으로 그리고 생성 된 코드에 대해 실제로 다음과 같은 차이점이 있습니까?
MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}
과
MyClass::MyClass()
{
_capacity=15;
_data=NULL;
_len=0
}
감사...
답변:
이러한 값이 기본 유형이라고 가정하면 차이가 없습니다. 초기화 목록은 개체가 멤버로있는 경우에만 차이가 있습니다. 기본 초기화와 할당을 사용하는 대신 초기화 목록을 사용하면 개체를 최종 값으로 초기화 할 수 있습니다. 이것은 실제로 눈에 띄게 더 빠를 수 있습니다.
상수 멤버, 참조 및 기본 클래스를 초기화하려면 초기화 목록을 사용해야합니다.
주석에서 언급했듯이 상수 멤버, 참조 및 매개 변수를 기본 클래스 생성자에 초기화해야하는 경우 초기화 목록을 사용해야합니다.
struct aa
{
int i;
const int ci; // constant member
aa() : i(0) {} // will fail, constant member not initialized
};
struct aa
{
int i;
const int ci;
aa() : i(0) { ci = 3;} // will fail, ci is constant
};
struct aa
{
int i;
const int ci;
aa() : i(0), ci(3) {} // works
};
예제 (완전하지 않은) 클래스 / 구조물에 참조가 포함되어 있습니다.
struct bb {};
struct aa
{
bb& rb;
aa(bb& b ) : rb(b) {}
};
// usage:
bb b;
aa a(b);
매개 변수가 필요한 기본 클래스를 초기화하는 예 (예 : 기본 생성자 없음) :
struct bb {};
struct dd
{
char c;
dd(char x) : c(x) {}
};
struct aa : dd
{
bb& rb;
aa(bb& b ) : dd('a'), rb(b) {}
};
_capacity
, _data
및 _len
접근 기본 생성자없이 클래스 유형이?
const
은 생성자의 본문에서 멤버를 초기화 할 수없고 초기화 목록을 사용해야한다는 것입니다. const
멤버가 아닌 멤버는 초기화 목록 또는 생성자 본문에서 초기화 할 수 있습니다.
예. 첫 번째 경우 _capacity
, _data
및 _len
상수로 선언 할 수 있습니다 .
class MyClass
{
private:
const int _capacity;
const void *_data;
const int _len;
// ...
};
const
예를 들어 런타임에 값을 계산하는 동안 이러한 인스턴스 변수의 -ness 를 보장하려는 경우 이는 중요합니다 .
MyClass::MyClass() :
_capacity(someMethod()),
_data(someOtherMethod()),
_len(yetAnotherMethod())
{
}
const
인스턴스 는 이니셜 라이저 목록에서 초기화 되거나 기본 유형이 매개 변수없는 공용 생성자를 제공해야합니다 (기본 유형이 수행함).
이 링크 http://www.cplusplus.com/forum/articles/17820/ 은 특히 C ++를 처음 접하는 사람들에게 훌륭한 설명을 제공 한다고 생각합니다 .
intialiser 목록이 더 효율적인 이유는 생성자 본문 내에서 초기화가 아닌 할당 만 발생하기 때문입니다. 따라서 내장되지 않은 유형을 다루는 경우 생성자의 본문이 입력되기 전에 해당 객체의 기본 생성자가 이미 호출되었습니다. 생성자 본문 내에서 해당 개체에 값을 할당합니다.
실제로 이것은 기본 생성자에 대한 호출과 복사 할당 연산자에 대한 호출입니다. 이니셜 라이저 목록을 사용하면 복사 생성자를 직접 호출 할 수 있으며 때로는 훨씬 더 빠를 수 있습니다 (이니셜 라이저 목록이 생성자 본문 앞에 있음을 기억하십시오).
실제 차이점은 gcc 컴파일러가 기계 코드를 생성하고 메모리를 배치하는 방법에 달려 있습니다. 설명:
const 유형 멤버를 처리하는 다른 방법이 확실히 있습니다. 그러나 삶을 편하게하기 위해 gcc 컴파일러 작성자는 몇 가지 규칙을 설정하기로 결정했습니다.
기본 클래스 인스턴스와 비 정적 멤버 변수 를 초기화하는 한 가지 방법은 이니셜 라이저 목록을 사용하는 것입니다.
생성자의 이니셜 라이저 목록에 기본 또는 비 정적 멤버 변수를 지정하지 않으면 해당 멤버 또는 기본이 기본값으로 초기화됩니다 (멤버 /베이스가 비 POD 클래스 유형이거나 비 POD 클래스의 배열 인 경우). 유형) 또는 초기화되지 않은 상태로 둡니다.
생성자 본문이 입력되면 모든 기본 또는 멤버가 초기화되거나 초기화되지 않은 상태로 남게됩니다 (즉, 불확실한 값을 갖게됩니다). 생성자 본문에는 초기화 방법에 영향을 줄 기회가 없습니다.
생성자 본문의 멤버에 새 값을 할당 할 수 있지만 할당 할 수 없게 된 const
클래스 유형의 멤버 나 멤버에는 할당 할 수 없으며 참조를 리 바인드 할 수 없습니다.
기본 제공 형식 및 일부 사용자 정의 형식의 경우 생성자 본문에 할당하면 이니셜 라이저 목록에서 동일한 값으로 초기화하는 것과 정확히 동일한 효과가있을 수 있습니다.
이니셜 라이저 목록에서 멤버 또는베이스의 이름을 지정하지 못하고 해당 엔티티가 참조이고 액세스 가능한 사용자 선언 기본 생성자가없는 클래스 유형이 있고 const
규정되고 POD 유형이 있거나 POD 클래스 유형 또는 POD 클래스 유형의 배열 인 경우 함유 const
규정하는 부재 (직접 또는 간접적으로) 그 프로그램이 잘못 형성된다.
이니셜 라이저 목록을 작성하면 모든 작업을 한 단계로 수행합니다. 이니 틸 라이저 목록을 작성하지 않으면 선언과 값 서명의 두 단계를 수행합니다.
생성자에서 초기화 목록과 초기화 문에는 차이가 있습니다. 아래 코드를 살펴 보겠습니다.
#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>
class MyBase {
public:
MyBase() {
std::cout << __FUNCTION__ << std::endl;
}
};
class MyClass : public MyBase {
public:
MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
std::cout << __FUNCTION__ << std::endl;
}
private:
int _capacity;
int* _data;
int _len;
};
class MyClass2 : public MyBase {
public:
MyClass2::MyClass2() {
std::cout << __FUNCTION__ << std::endl;
_capacity = 15;
_data = NULL;
_len = 0;
}
private:
int _capacity;
int* _data;
int _len;
};
int main() {
MyClass c;
MyClass2 d;
return 0;
}
MyClass를 사용하면 생성자의 첫 번째 문이 실행되기 전에 모든 멤버가 초기화됩니다.
그러나 MyClass2를 사용하면 생성자의 첫 번째 문이 실행될 때 모든 멤버가 초기화되지 않습니다.
나중에 특정 멤버가 초기화되기 전에 누군가 생성자에 일부 코드를 추가하면 회귀 문제가 발생할 수 있습니다.
다른 사람들이 언급하지 않은 점은 다음과 같습니다.
class temp{
public:
temp(int var);
};
임시 클래스에는 기본 ctor가 없습니다. 다음과 같이 다른 클래스에서 사용할 때 :
class mainClass{
public:
mainClass(){}
private:
int a;
temp obj;
};
코드가 컴파일되지 않고 컴파일러가 초기화하는 방법을 모르기 obj
때문에 int 값을받는 명시 적 ctor가 있으므로 다음과 같이 ctor를 변경해야합니다.
mainClass(int sth):obj(sth){}
따라서 그것은 단지 const와 reference에 관한 것이 아닙니다!