문제

배경

내부적으로 vector<std::string> 을 사용하는 컨테이너 클래스가 있습니다.나는 방법을 제공했다 AddChar(표준::문자열) 이 래퍼 클래스에 push_back() 내부 벡터에.내 코드에서는 한동안 컨테이너에 여러 항목을 추가해야 합니다.그러기 위해서는 내가 사용해야하는

container.AddChar("First");
container.AddChar("Second");

이렇게 하면 코드가 더 커집니다.그래서 더 쉽게 하기 위해 연산자 <<를 오버로드할 계획입니다.내가 쓸 수 있게

container << "First" << "Second"

두 개의 항목이 기본 벡터에 추가됩니다.

여기에 내가 사용한 코드가 있습니다.

class ExtendedVector
{
private:
    vector<string> container;

public:
    friend ExtendedVector& operator<<(ExtendedVector& cont,const std::string str){
        cont.AddChar(str);
        return cont;
    }

    void AddChar(const std::string str)
    {
        container.push_back(str);
    }

    string ToString()
    {
        string output;
        vector<string>::iterator it = container.begin();
        while(it != container.end())
        {
            output += *it;
            ++it;
        }
        return output;
    }
};

예상대로 작동하고 있습니다.

질문

  1. 연산자 오버로드가 올바르게 작성되었습니까?
  2. 이와 같은 상황에서는 연산자를 오버로드하는 것이 좋은 습관입니까?
  3. 이 코드에 성능 문제나 다른 문제가 있습니까?

이견있는 사람?

편집하다

훌륭한 의견을 들은 후, 여기서는 말이 안 되기 때문에 <<를 오버로드하지 않기로 결정했습니다.연산자 오버로드 코드를 제거했으며 여기에 최종 코드가 있습니다.

class ExtendedVector
{
private:
    vector<string> container;

public:

    ExtendedVector& AddChar(const std::string str)
    {
        container.push_back(str);
        return *this;
    }

         .. other methods
}

이를 통해 추가할 수 있습니다.

container.AddChar("First").AddChar("Second")

C#에서는 params 키워드를 사용하여 이 작업을 더 쉽게 수행할 수 있습니다.코드는 다음과 같습니다

void AddChar(params string[] str)
{
    foreach(string s in str)
       // add to the underlying collection
}

C++에서는 다음을 사용할 수 있다는 것을 알고 있습니다. ... 매개변수의 가변 길이를 지정합니다.그러나 AFAIK는 유형이 안전하지 않습니다.그렇다면 그렇게 하는 것이 권장되는 방법입니까?내가 쓸 수 있게

container.AddChar("First","Second")

답장을 보내주셔서 감사합니다.

도움이 되었습니까?

해결책

연산자 오버로드가 올바르게 작성되었습니까?

그렇습니다. 그러나 더 잘할 수 있습니다.다른 사람이 언급한 것처럼 귀하의 함수는 기존 공개 함수에서 완전히 정의될 수 있습니다.그것만 사용하도록 만드는 것은 어떨까요?지금은 친구입니다. 이는 구현 세부정보에 속한다는 의미입니다.연산자<<를 클래스의 멤버로 넣는 경우에도 마찬가지입니다.그러나 연산자<<를 비 멤버, 친구가 아닌 기능.

class ExtendedVector {
    ...
};

// note, now it is *entirely decoupled* from any private members!
ExtendedVector& operator<<(ExtendedVector& cont, const std::string& str){
    cont.AddChar(str);
    return cont;
}

클래스를 변경하면 연산자<<가 계속 작동하는지 확신할 수 없습니다.그러나 연산자<<가 전적으로 공용 함수에만 의존하는 경우 클래스의 구현 세부 사항만 변경한 후에만 작동할 것이라고 확신할 수 있습니다.이야!

이와 같은 상황에서는 연산자를 오버로드하는 것이 좋은 습관입니까?

다른 사람이 다시 말했듯이 이것은 논쟁의 여지가 있습니다.많은 상황에서 연산자 오버로드는 첫눈에 "깔끔"해 보이지만 내년에는 지옥처럼 보일 것입니다. 왜냐하면 일부 기호에 특별한 사랑을 줄 때 무엇을 염두에 두었는지 더 이상 알 수 없기 때문입니다.연산자<<의 경우에는 이것이 괜찮은 사용이라고 생각합니다.스트림에 대한 삽입 연산자로 사용되는 것은 잘 알려져 있습니다.그리고 나는 다음과 같은 경우에 그것을 광범위하게 사용하는 Qt와 KDE 응용 프로그램을 알고 있습니다.

QStringList items; 
items << "item1" << "item2";

비슷한 경우는 boost.format 이는 또한 재사용 operator% 문자열의 자리 표시자에 대한 인수를 전달하려면 다음을 수행하세요.

format("hello %1%, i'm %2% y'old") % "benny" % 21

물론 거기에서 사용하는 것도 논쟁의 여지가 있습니다.그러나 printf 형식 지정에 대한 사용은 잘 알려져 있으므로 거기에서도 사용이 가능합니다.하지만 늘 그렇듯이 스타일도 주관적이므로 소금 한 알씩 섭취해 주세요 :)

유형이 안전한 방식으로 가변 길이 인수를 어떻게 받아들일 수 있나요?

음, 동질적인 인수를 찾고 있다면 벡터를 받아들이는 방법이 있습니다:

void AddChars(std::vector<std::string> const& v) {
    std::vector<std::string>::const_iterator cit =
        v.begin();
    for(;cit != v.begin(); ++cit) {
        AddChar(*cit);
    }
}

그래도 통과하기에는 별로 불편하지 않습니다.벡터를 수동으로 구성한 다음 통과해야 합니다.나는 당신이 이미 vararg 스타일 함수에 대해 올바른 느낌을 가지고 있다고 봅니다.이러한 종류의 코드에는 사용해서는 안 되며, C 코드와 인터페이스하거나 디버깅 기능을 사용할 때만 사용해야 합니다.이 경우를 처리하는 또 다른 방법은 전처리기 프로그래밍을 적용하는 것입니다.이것은 고급 주제이고 상당히 해키적입니다.아이디어는 대략 다음과 같이 일부 상한까지 과부하를 자동으로 생성하는 것입니다.

#define GEN_OVERLOAD(X) \
void AddChars(GEN_ARGS(X, std::string arg)) { \
    /* now access arg0 ... arg(X-1) */ \
    /* AddChar(arg0); ... AddChar(arg(N-1)); */ \
    GEN_PRINT_ARG1(X, AddChar, arg) \
}

/* call macro with 0, 1, ..., 9 as argument
GEN_PRINT(10, GEN_OVERLOAD)

그것은 의사 코드입니다.부스트 전처리기 라이브러리를 살펴볼 수 있습니다. 여기.

다음 C++ 버전은 훨씬 더 나은 가능성을 제공할 것입니다.초기화 목록을 사용할 수 있습니다:

void AddChars(initializer_list<std::string> ilist) {
    // range based for loop
    for(std::string const& s : ilist) {
        AddChar(s);
    }
}

...
AddChars({"hello", "you", "this is fun"});

다음 C++에서는 다음을 사용하여 임의의 많은(혼합 유형) 인수를 지원하는 것도 가능합니다. 가변 템플릿.GCC4.4는 이를 지원할 것입니다.GCC 4.3에서는 이미 부분적으로 지원합니다.

다른 팁

1) 예, AddChar가 공개되기 때문에 friend.

2) 이것은 논쟁의 여지가 있습니다. << "이상한"물건에 대한 과부하가 적어도 끔찍하게 받아 들여지는 운영자가되는 위치에 있습니다.

3) 분명한 것은 없습니다. 항상 그렇듯이 프로파일 링은 친구입니다. 문자열 매개 변수를 전달하는 것을 고려할 수 있습니다. AddChar 그리고 operator<< const 참조로 (const std::string&) 불필요한 복사를 피하기 위해.

이와 같은 상황에서 운영자를 과부하시키는 것이 좋은 관행입니까?

나는 그렇게 생각하지 않습니다. 당신이 운영자에 과부하가 걸렸다는 것을 모르는 사람에게는 혼란 스럽습니다. 설명 방법 이름을 고수하고 입력하는 추가 캐릭터를 잊어 버리십시오. 그만한 가치가 없습니다. 당신의 관리자 (또는 당신은 6 개월 후에 당신 자신)에게 감사 할 것입니다.

벡터가 일반적으로 과부하 된 왼쪽 시프트 연산자가 없기 때문에 개인적으로 그런 식으로 과부하하지 않기를 원합니다. 실제로는 관용구가 아닙니다 ;-)

나는 아마도 다음과 같은 addchar에서 참조를 반환 할 것입니다.

ExtendedVector& AddChar(const std::string& str) {
    container.push_back(str);
    return *this;
}

그러면 할 수 있습니다

container.AddChar("First").AddChar("Second");

비트 시프트 연산자보다 크지 않습니다.

(또한 값 대신 참조로 문자열을 전달하는 것에 대한 Logan의 의견을 참조하십시오).

이 경우 연산자 과부하는 코드를 덜 읽기 쉽게 만들기 때문에 모범 사례가 아닙니다. 표준 std::vector 적절한 이유로 요소를 밀기위한 것이 없습니다.

발신자 코드가 너무 길어질까 걱정된다면 과부하가 걸린 연산자 대신이를 고려할 수 있습니다.

container.AddChar("First").AddChar("Second");

당신이 있다면 이것은 가능할 것입니다 AddChar() 반품 *this.

당신이 이것을 가지고 있다는 것은 재밌습니다 toString() 기능. ~ 안에 저것 케이스, an operator<< 스트림에 출력하는 것은 대신 사용하는 표준입니다! 따라서 운영자를 사용하려면 toString() 기능 an operator<<.

운영자는 여기에 올바르게 과부하되지 않습니다. 수업의 회원이 될 수 있기 때문에 운영자를 친구로 만들 이유가 없습니다. 친구는 클래스의 실제 구성원이 아닌 함수를위한 것입니다 (오버로드 <<< Ostream의 경우 객체가 cout 또는 ofstream에 출력 할 수 있음).

실제로 운영자가 원하는 것 :

ExtendedVector& operator<<(const std::string str){
    AddChar(str);
    return *this;
}

일반적으로 운영자가 정상적으로하는 것보다 무언가를하는 방식으로 오버로드하는 것은 나쁜 관행으로 간주됩니다. <<는 일반적으로 비트 변속이므로 이런 식으로 과부하가 혼란 스러울 수 있습니다. 분명히 STL 과부하 << << "스트림 삽입"에 대해서는 그와 함께 ~할 것 같다 비슷한 방식으로 사용하기 위해 과부하가됩니다. 그러나 그것은 당신이하는 일처럼 보이지 않으므로 아마 그것을 피하고 싶을 것입니다.

연산자 과부하가 일반 기능 호출과 동일하기 때문에 성능 문제가 없습니다. 컴파일러가 자동으로 수행되므로 호출 만 숨겨져 있습니다.

이것은 일을 다소 혼란스럽게 만들 것입니다. 나는 std :: cin과 같은 구문을 변수로 사용합니다.

std::cin >> someint;

"First" >> container;

이런 식으로 적어도 삽입 연산자입니다. << 과부하가있는 연산자가 있으면 나에게 무언가를 출력 할 것으로 기대합니다. std :: cout처럼.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top