C++
하나의 정의 규칙 (ODR)
수색…
정의 된 함수 곱하기
One Definition Rule의 가장 중요한 결과는 외부 링키지가있는 인라인이 아닌 함수는 여러 번 선언 할 수 있지만 프로그램에서 한 번만 정의해야한다는 것입니다. 따라서 헤더가 여러 번역 단위에서 여러 번 포함될 수 있으므로 이러한 함수를 헤더에 정의하면 안됩니다.
foo.h
:
#ifndef FOO_H
#define FOO_H
#include <iostream>
void foo() { std::cout << "foo"; }
void bar();
#endif
foo.cpp
:
#include "foo.h"
void bar() { std:: cout << "bar"; }
main.cpp
:
#include "foo.h"
int main() {
foo();
bar();
}
이 프로그램에서 함수 foo
는 헤더 foo.h
정의되어 있습니다. foo.h
는 foo.cpp
에서 한 번, main.cpp
에서 한 번 두 번 포함됩니다. 따라서 각 번역 단위에는 foo
대한 자체 정의가 들어 있습니다. foo.h
의 include guards는 foo.cpp
와 main.cpp
둘 다 foo.h
별도로 포함하기 때문에 발생하지 않도록주의하십시오. 이 프로그램을 빌드하려고했을 때 가장 많이 발생하는 결과는 foo
가 여러 번 정의 된 것으로 식별하는 링크 타임 오류입니다.
이러한 오류를 방지하려면 몇 가지 예외를 제외하고는 헤더에 함수를 선언 하고 해당 .cpp
파일에서 함수를 정의 해야합니다 (다른 예제 참조).
인라인 함수
inline
선언 된 함수는 모든 정의가 동일한 경우 여러 번역 단위로 정의 될 수 있습니다. 또한 사용되는 모든 번역 단위에서 정의되어야합니다. 따라서 인라인 함수 는 헤더에 정의 되어야 하며 구현 파일에서 인라인 함수를 언급 할 필요가 없습니다.
프로그램은 함수 정의가 하나 인 것처럼 동작합니다.
foo.h
:
#ifndef FOO_H
#define FOO_H
#include <iostream>
inline void foo() { std::cout << "foo"; }
void bar();
#endif
foo.cpp
:
#include "foo.h"
void bar() {
// more complicated definition
}
main.cpp
:
#include "foo.h"
int main() {
foo();
bar();
}
이 예제에서 더 간단한 함수 foo
는 헤더 파일에서 인라인으로 정의되지만보다 복잡한 함수 bar
는 인라인이 아니며 구현 파일에 정의됩니다. foo.cpp
및 main.cpp
번역 단위는 모두 foo
정의를 포함하지만이 프로그램은 foo
가 인라인이므로 올바른 형식입니다.
클래스 정의 내에서 정의 된 함수 (멤버 함수 또는 friend 함수 일 수 있음)는 암시 적으로 인라인입니다. 따라서 클래스가 헤더에 정의 된 경우 정의가 여러 번역 단위에 포함될 수는 있지만 클래스의 멤버 함수가 클래스 정의 내에 정의 될 수 있습니다.
// in foo.h
class Foo {
void bar() { std::cout << "bar"; }
void baz();
};
// in foo.cpp
void Foo::baz() {
// definition
}
기능 Foo::baz
아웃 오브 라인 정의, 그래서 인라인 함수 아니며, 헤더에 정의되어서는 안된다.
과부하 해결을 통한 ODR 위반
인라인 함수에 대해 동일한 토큰이 있더라도 이름 조회가 동일한 엔티티를 참조하지 않으면 ODR이 위반 될 수 있습니다. 다음과 같은 func
를 고려해 보겠습니다.
header.h
void overloaded(int); inline void func() { overloaded('*'); }
foo.cpp
#include "header.h" void foo() { func(); // `overloaded` refers to `void overloaded(int)` }
bar.cpp
void overloaded(char); // can come from other include #include "header.h" void bar() { func(); // `overloaded` refers to `void overloaded(char)` }
overloaded
된 ODR 위반은 번역 단위에 따라 다른 엔티티를 나타냅니다.