수색…


통사론

  • // 전화 :

    • variable.member_function ();
    • variable_pointer-> member_function ();
  • // 정의 :

    • ret_type class_name :: member_function () cv-qualifiers {
      • 신체;
    • }
  • // 프로토 타입 :

    • class class_name {
      • virt-specifier ret_type member_function () cv-qualifiers virt-specifier-seq;
      • // virt-specifier : 해당되는 경우 "virtual".
      • // cv-qualifiers : "const"및 / 또는 "volatile"(해당되는 경우).
      • // virt-specifier-seq : "override"및 / 또는 "final"(해당되는 경우).
    • }

비고

static 멤버 함수는 class / struct / union 멤버 함수로, 특정 인스턴스에서 호출되며 해당 인스턴스에서 작동합니다. static 멤버 함수와 달리 인스턴스를 지정하지 않으면 호출 할 수 없습니다.

클래스, 구조체 및 공용체에 대한 자세한 내용 은 상위 항목을 참조하십시오.

비 정적 멤버 함수

classstruct 는 멤버 함수와 멤버 변수를 가질 수 있습니다. 이 함수는 독립형 함수와 거의 유사한 구문을 가지며 클래스 정의 내부 또는 외부에서 정의 할 수 있습니다. 클래스 정의 외부에서 정의 된 경우 함수의 이름 앞에는 클래스 'name 및 범위 ( :: 연산자 접두어가 붙습니다.

class CL {
  public:
    void  definedInside() {}
    void definedOutside();
};
void CL::definedOutside() {}

이 함수는 점 ( . ) 연산자가있는 클래스의 인스턴스 (또는 인스턴스 참조)에서 호출되거나 화살표 ( -> ) 연산자가있는 인스턴스에 대한 포인터로 호출되며 각 호출은 함수 인스턴스에 연결됩니다 에 불려졌다. 멤버 함수가 인스턴스에서 호출되면 this 포인터를 통해 해당 인스턴스의 모든 필드에 액세스 할 수 있지만 해당 인스턴스가 매개 변수로 제공되면 다른 인스턴스의 필드에만 액세스 할 수 있습니다.

struct ST {
    ST(const std::string& ss = "Wolf", int ii = 359) : s(ss), i(ii) { }

    int get_i() const { return i; }
    bool compare_i(const ST& other) const { return (i == other.i); }

  private:
    std::string s;
    int i;
};
ST st1;
ST st2("Species", 8472);

int  i = st1.get_i(); // Can access st1.i, but not st2.i.
bool b = st1.compare_i(st2); // Can access st1 & st2.

이러한 함수는 변수 또는 함수의 액세스 수정 자에 관계없이 멤버 변수 및 / 또는 다른 멤버 함수에 액세스 할 수 있습니다. 또한 컴파일러가 클래스를 컴파일하기 전에 전체 클래스 정의를 파싱해야하므로 멤버 변수 및 / 또는 호출 멤버 함수에 액세스하여 순서가 없어도 쓸 수 있습니다.

class Access {
  public:
    Access(int i_ = 8088, int j_ = 8086, int k_ = 6502) : i(i_), j(j_), k(k_) {}

    int i;
    int get_k() const { return k; }
    bool private_no_more() const { return i_be_private(); }
  protected:
    int j;
    int get_i() const { return i; }
  private:
    int k;
    int get_j() const { return j; }
    bool i_be_private() const { return ((i > j) && (k < j)); }
};

캡슐화

멤버 함수의 일반적인 사용 대신 직접 필드 액세스 (통상적 게터라고도 함) 및 접근 (통상적 세터라고도 함) 테이터를 사용하여 캡슐화한다.

class Encapsulator {
    int encapsulated;

  public:
    int  get_encapsulated() const { return encapsulated; }
    void set_encapsulated(int e)  { encapsulated = e; }

    void some_func() {
        do_something_with(encapsulated);
    }
};

클래스 내에서 encapsulated 된 클래스는 비 정적 멤버 함수로 자유롭게 액세스 할 수 있습니다. 클래스 외부 그것에 액세스를 사용하여, 멤버 함수에 의해 조절된다 get_encapsulated() 를 판독하고 set_encapsulated() 수정하기. 이렇게하면 변수를 읽고 쓰는 데 별도의 함수가 사용되므로 변수가 의도하지 않게 수정되는 것을 방지 할 수 있습니다. [게터와 세터가 캡슐화를 제공하거나 중단하는지에 대한 많은 논의가 있으며 두 주장 모두에 대해 좋은 논거가있다. 그러한 논쟁은이 예에서 다루지 않는다.]

이름 숨기기 및 가져 오기

기본 클래스가 오버로드 된 함수 집합을 제공하고 파생 클래스가 집합에 또 다른 오버로드를 추가하면 기본 클래스에서 제공하는 모든 오버로드를 숨 깁니다.

struct HiddenBase {
    void f(int) { std::cout << "int" << std::endl; }
    void f(bool) { std::cout << "bool" << std::endl; }
    void f(std::string) { std::cout << "std::string" << std::endl; }
};

struct HidingDerived : HiddenBase {
    void f(float) { std::cout << "float" << std::endl; }
};

// ...

HiddenBase hb;
HidingDerived hd;
std::string s;

hb.f(1);    // Output:  int
hb.f(true); // Output:  bool
hb.f(s);    // Output:  std::string;

hd.f(1.f);  // Output:  float
hd.f(3);    // Output:  float
hd.f(true); // Output:  float
hd.f(s);    // Error: Can't convert from std::string to float.

이것은 이름 해석 규칙 때문입니다. 이름 조회 중에 올바른 이름을 찾으면 해당 이름을 가진 엔티티의 올바른 버전 을 분명히 찾지 hd.f(s) 예 : hd.f(s) ); 이로 인해 파생 클래스에서 함수를 오버로드하면 이름 조회가 기본 클래스에서 오버로드를 발견하지 못합니다. 이를 피하기 위해 using 선언을 사용하여 기본 클래스에서 파생 클래스로 이름을 "가져와"이름 조회 중에 사용할 수 있습니다.

struct HidingDerived : HiddenBase {
     // All members named HiddenBase::f shall be considered members of HidingDerived for lookup.
    using HiddenBase::f;

    void f(float) { std::cout << "float" << std::endl; }
};

// ...

HidingDerived hd;

hd.f(1.f);  // Output:  float
hd.f(3);    // Output:  int
hd.f(true); // Output:  bool
hd.f(s);    // Output:  std::string

파생 클래스가 using 선언을 사용하여 이름을 가져 오지만 기본 클래스의 함수와 동일한 서명으로 함수를 선언하면 기본 클래스 함수가 ​​자동으로 재정의되거나 숨겨집니다.

struct NamesHidden {
    virtual void hide_me()      {}
    virtual void hide_me(float) {}
    void hide_me(int)           {}
    void hide_me(bool)          {}
};

struct NameHider : NamesHidden {
    using NamesHidden::hide_me;

    void hide_me()    {} // Overrides NamesHidden::hide_me().
    void hide_me(int) {} // Hides NamesHidden::hide_me(int).
};

가져온 엔티티가 public 되거나 기본 클래스에서 protected 된 경우 using 선언을 사용하여 액세스 수정자를 변경할 수도 있습니다.

struct ProMem {
  protected:
    void func() {}
};

struct BecomesPub : ProMem {
    using ProMem::func;
};

// ...

ProMem pm;
BecomesPub bp;

pm.func(); // Error: protected.
bp.func(); // Good.

마찬가지로 상속 계층의 특정 클래스에서 멤버 함수를 명시 적으로 호출하려는 경우 해당 함수를 호출 할 때 함수 이름을 정규화하고 해당 클래스를 이름으로 지정할 수 있습니다.

struct One {
    virtual void f() { std::cout << "One." << std::endl; }
};

struct Two : One {
    void f() override {
        One::f(); // this->One::f();
        std::cout << "Two." << std::endl;
    }
};

struct Three : Two {
    void f() override {
        Two::f(); // this->Two::f();
        std::cout << "Three." << std::endl;
    }
};

// ...

Three t;

t.f();      // Normal syntax.
t.Two::f(); // Calls version of f() defined in Two.
t.One::f(); // Calls version of f() defined in One.

가상 멤버 함수

멤버 함수는 virtual 으로 선언 할 수도 있습니다. 이 경우, 포인터 또는 인스턴스에 대한 참조에서 호출되면 직접 액세스하지 않습니다. 오히려 가상 함수 테이블 ( vtable 또는 vftable 이라고하는 가상 함수에 대한 포인터 - 구성원 함수 함수의 목록)에서 함수를 vftable 하고이를 사용하여 인스턴스의 동적에 적합한 버전을 호출합니다 (실제) 유형. 함수가 클래스의 변수에서 직접 호출되면 조회가 수행되지 않습니다.

struct Base {
    virtual void func() { std::cout << "In Base." << std::endl; }
};

struct Derived : Base {
    void func() override { std::cout << "In Derived." << std::endl; }
};

void slicer(Base x) { x.func(); }

// ...

Base b;
Derived d;

Base *pb = &b, *pd = &d; // Pointers.
Base &rb = b, &rd = d;   // References.

b.func();   // Output:  In Base.
d.func();   // Output:  In Derived.

pb->func(); // Output:  In Base.
pd->func(); // Output:  In Derived.

rb.func();  // Output:  In Base.
rd.func();  // Output:  In Derived.

slicer(b);  // Output:  In Base.
slicer(d);  // Output:  In Base.

참고하면서 pd 것입니다 Base*rd A는 Base& 호출 func() 두 통화 중 하나에서 Derived::func() 대신 Base::func() ; 왜냐하면 Derived 대한 vtableBase::func() 항목을 대신 Derived::func() 업데이트하기 때문입니다. 반대로, 인스턴스를 slicer() 에 전달하면 전달 된 인스턴스가 Derived 클래스 인 경우에도 Base::func() 가 호출됩니다. 이것은 Derived 인스턴스를 값으로 Base 매개 변수에 전달하면 Base 인스턴스가 아닌 Derived 인스턴스의 일부를 액세스 할 수 없게 만드는 데이터 슬라이싱으로 알려져 있습니다.

멤버 함수가 가상으로 정의되면 재정의 함수가 virtual 으로 지정되었는지 여부에 관계없이 동일한 서명이있는 파생 클래스 멤버 함수가 모두 재정의됩니다. 그러나 이것은 프로그래머가 파싱 할 때 파생 클래스를 더 어렵게 만들 수 있습니다. 그러나 어떤 함수가 virtual .

struct B {
    virtual void f() {}
};

struct D : B {
    void f() {} // Implicitly virtual, overrides B::f.
                //  You'd have to check B to know that, though.
};

그러나 파생 함수는 서명이 일치하면 기본 함수를 재정의합니다. 파생 된 함수가 명시 적으로 virtual 으로 선언 된 경우에도 서명이 일치하지 않으면 대신 새 가상 함수를 만듭니다.

struct BadB {
    virtual void f() {}
};

struct BadD : BadB {
    virtual void f(int i) {} // Does NOT override BadB::f.
};
C ++ 11

C ++ 11부터는 재정의 할 의도가 상황에 맞는 키워드 override 로 명시 될 수 있습니다. 이것은 프로그래머가 기본 클래스 함수를 재정 의하여 컴파일러가 아무 것도 재정의 하지 않으면 오류를 생략 할 것으로 예상한다는 것을 컴파일러에 알립니다.

struct CPP11B {
    virtual void f() {}
};

struct CPP11D : CPP11B {
    void f() override {}
    void f(int i) override {} // Error: Doesn't actually override anything.
};

또한 프로그래머에게 함수가 가상이고 적어도 하나의 기본 클래스로 선언되어 복잡한 클래스를 더 쉽게 구문 분석 할 수 있다고 알려주는 이점이 있습니다.

함수가 virtual 으로 선언되고 클래스 정의 외부에서 정의되는 경우 virtual 지정자는 함수 선언에 포함되어야하며 정의에서 반복되지 않아야합니다.

C ++ 11

이것은 override 에도 override 됩니다.

struct VB {
    virtual void f(); // "virtual" goes here.
    void g();
};
/* virtual */ void VB::f() {} // Not here.
virtual void VB::g() {} // Error.

기본 클래스가 과부하 경우 virtual 함수를 명시 적으로 지정된 경우에만 과부하 virtual 가상 될 것입니다.

struct BOverload {
    virtual void func() {}
    void func(int) {}
};

struct DOverload : BOverload {
    void func() override {}
    void func(int) {}
};

// ...

BOverload* bo = new DOverload;
bo->func(); // Calls DOverload::func().
bo->func(1); // Calls BOverload::func(int).

자세한 내용 은 관련 항목을 참조하십시오.

Const 정확함

this cv 한정자의 기본 용도 중 하나는 const 정확성 입니다. 이것은 단지 개체를 수정할 있으며, 객체를 수정하는 것을 필요에 액세스하는 보장의 방법입니다 그 어떤 (회원 또는 비회원)가 쓰기 액세스 권한이없는 개체를 수정할 필요가없는 기능 객체 (직접 또는 간접적으로). 이렇게하면 의도하지 않은 수정을 방지하여 코드 오류를 줄일 수 있습니다. 또한 함수를 재 작성하거나 오버로드 할 필요없이 상태를 수정할 필요가없는 모든 함수에서 const 또는 non- const 오브젝트를 사용할 수 있습니다.

const 정확성은 그 본성으로 인해 아래쪽부터 시작됩니다. 상태를 변경할 필요가없는 클래스 멤버 함수는 const선언 되므로 const 인스턴스에서 호출 할 수 있습니다. 이것은 차례로, 참조에 의해 전달 된 매개 변수가 수정 될 필요가 없을 때 const 로 선언 될 수있게합니다.이 함수는 함수가 const 또는 non- const 오브젝트를 불평하지 않고 취할 수있게하며, const -ness는이를 바깥쪽으로 전파 할 수 있습니다 방법. 이 때문에 getter는 논리 상태를 수정할 필요가없는 다른 함수와 마찬가지로 const 가 빈번합니다.

class ConstIncorrect {
    Field fld;

  public:
    ConstIncorrect(const Field& f) : fld(f) {}     // Modifies.

    const Field& get_field()       { return fld; } // Doesn't modify; should be const.
    void set_field(const Field& f) { fld = f; }    // Modifies.

    void do_something(int i) {                     // Modifies.
        fld.insert_value(i);
    }
    void do_nothing()        { }                   // Doesn't modify; should be const.
};

class ConstCorrect {
    Field fld;

  public:
    ConstCorrect(const Field& f) : fld(f) {}       // Not const: Modifies.

    const Field& get_field() const { return fld; } // const: Doesn't modify.
    void set_field(const Field& f) { fld = f; }    // Not const: Modifies.

    void do_something(int i) {                     // Not const: Modifies.
        fld.insert_value(i);
    }
    void do_nothing() const  { }                   // const: Doesn't modify.
};

// ...

const ConstIncorrect i_cant_do_anything(make_me_a_field());
// Now, let's read it...
Field f = i_cant_do_anything.get_field();
  // Error: Loses cv-qualifiers, get_field() isn't const.
i_cant_do_anything.do_nothing();
  // Error: Same as above.
// Oops.

const ConstCorrect but_i_can(make_me_a_field());
// Now, let's read it...
Field f = but_i_can.get_field(); // Good.
but_i_can.do_nothing();          // Good.

ConstIncorrectConstCorrect 에 대한 주석에 설명 된 것처럼 적절한 cv 한정 함수도 설명서의 역할을합니다. 클래스 인 경우 const , 수정되지 않은 함수 const 안전한 상태를 변경하는 것으로 가정 될 수 있고, 임의의 함수 const 안전한 상태를 변경하지 않는 것으로 가정 할 수있다.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow