반응형

 

 

friend 선언

- 접근지시자에 관계없이 모든 멤버의 접근을 허용하는 선언이다.

  ※ 그렇기 때문에, 클래스의 friend 선언은 객체 지향의 정보 은닉 개념에 위배된다.

- friend는 사용되는 클래스에서 선언을 해줘야한다.

- friend 선언은 클래스나 특정 멤버함수, 전역함수를 대상으로 사용이 가능하다.

 

  • 클래스 대상 friend
#include <iostream>
using namespace std;

class A
{
private:
    int n1;
    float f1;

public:
    A(int i, float f) : n1(i), f1(f) { }
    friend class B;
};

class B
{
private:
    int n1;
    float f1;

public:
    B() { }
    void Show()
    {
        cout << n1 << " / " << f1 << endl;
    }
    void Copy(A& a)
    {
        this->n1 = a.n1;
        this->f1 = a.f1;
    }
};

void main()
{
    A a(10, 10.5f);
    B b;
    b.Copy(a);
    b.Show();
    
    //결과 : 10 / 10.5
}

 

 

  • 멤버함수, 전역함수 대상 friend
#include <iostream>
using namespace std;
class Point;

class PointCalc
{
public:
    PointCalc() { }
    Point Add(const Point& p1, const Point& p2);
};

class Point
{
private:
    int x, y;

public:
    Point(int _x, int _y) : x(_x), y(_y) { }
    //1. PointCalc의 Add 함수에 대해 friend선언을 하고있다.
    friend Point PointCalc::Add(const Point& p1, const Point& p2);
    //2. 전역함수에 대해 friend선언을 하고있다.
    friend void ShowPoint(const Point& p1);
};

//1. 멤버함수 구현
Point PointCalc::Add(const Point& p1, const Point& p2)
{
    return Point(p1.x + p2.x, p1.y + p2.y);
}

//2. 전역함수 구현
void ShowPoint(const Point& p1)
{
    cout << "x : " << p1.x << " / y : " << p1.y << endl;
}

void main()
{
    Point p1(10, 20);
    Point p2(30, 40);
    PointCalc pc;
    
    ShowPoint(pc.Add(p1, p2));
    
    //결과 : x : 40 / y : 60
}

 

 

 

 

friend 선언시 주의점

- 위에서 언급했듯이 friend선언을 하게되면 모든 멤버에 접근이 가능하게 되므로 객체지향의 은닉성을 위배한다.

- 얽혀있는 클래스의 관계를 풀기위한 friend선언은 더 큰 문제를 야기하므로 사용하지 않는것이 좋다.

- friend 선언의 좋은 예는 연산자 오버로딩을 할 시, 교환법칙을 성립시키기 위한 사용법이 있다.

 

 

반응형

'Stack > C++' 카테고리의 다른 글

C++ 네임스페이스(namespace), using  (0) 2021.12.12
C++ 연산자 오버로딩  (0) 2021.12.05
C++ 다중상속  (0) 2021.11.22
C++ 멤버함수, 가상함수 동작원리  (0) 2021.11.17
C++ 순수 가상함수, 추상 클래스  (0) 2021.11.11
반응형

 

다중 상속 (Multiple Inheritance)

- 부모 클래스를 둘 이상 동시에 상속하는 것을 말한다.

- C++은 다중 상속을 지원하는 언어이다.

- 득보다 실이 많은 문법이라 알아만 두고 사용은 하지말것.

  ※ JAVA, C#에서만 보더라도 다중 상속을 지원하지 않는다.

 

 

 

다중 상속의 모호성

1. 다중 상속의 둘 이상의 부모 클래스의 동일한 이름의 멤버가 존재하는경우 문제가 발생한다.

#include <iostream>
using namespace std;

class Parent_1
{
public:
    void Func()
    {
        cout << "Parent_1 func." << endl;
    }
};

class Parent_2
{
public:
    void Func()
    {
        cout << "Parent_2 func." << endl;
    }
};

class Child : public Parent_1, public Parent_2
{
public:
    void ChildFunc()
    {
        //에러
        Func();
        Func();
    }
};

void main()
{
    Child child;
    child.ChildFunc();
}
  • 코드를 실행하면 Func()함수의 모호성을 컴파일에러로 뱉는다.

- 위와 같은 모호성에는 다음과 같이 호출 함수 앞에 클래스를 명시해줘야한다.

void ChildFunc()
{
    Parent_1::Func();
    Parent_2::Func();
}

 

 

2. 다중상속의 대상이 되는 부모 클래스(B, C)가 같은 부모 클래스(A)를 상속을 한 클래스일 때, 자식 클래스의 객체 내에 두 개의 A 클래스 멤버가 존재하는 문제가 발생한다.

#include <iostream>
using namespace std;

class A
{
public:
    A()
    {
        cout << "A Constructor" << endl;
    }
    void Func()
    {
        cout << "A func." << endl;
    }
};

class B : public A
{
public:
    B()
    {
        cout << "B Constructor" << endl;
    }
};

class C : public A
{
public:
    C()
    {
        cout << "C Constructor" << endl;
    }
};

class D : public B, public C
{
public:
    D()
    {
        cout << "D Constructor" << endl;
    }
    void ChildFunc()
    {
        B::Func();
        C::Func();
    }
};

void main()
{
    D d;
    d.ChildFunc();
    
    //결과
    //A Constructor
    //B Constructor
    //A Constructor
    //C Constructor
    //D Constructor
    //A Func.
    //A Func.
}
  • ChildFunc() 함수를 보면 간접적으로 상속한 A 클래스의 Func()함수를 호출하기 위해 함수 앞에 A를 명시해 모호성을 제거해줬다.
  • 결과를 확인해보면 D 클래스의 객체에서 A 클래스가 2개 존재하는것을 확인할 수 있다.
  • 위와 같은 중복 상속을 해결하기 위한 문법이 '가상 상속'이다.

- 위 코드에서 A 클래스는 중복 상속될 필요가 없으므로 B, C 클래스에서 'virtual' 키워드로 가상 상속한다.

class B : virtual public A { . . };
class C : virtual public A { . . };
class D : public B, public c { . . };

//결과
//A Constructor
//B Constructor
//C Constructor
//D Constructor

 

반응형

'Stack > C++' 카테고리의 다른 글

C++ 연산자 오버로딩  (0) 2021.12.05
C++ friend  (0) 2021.12.05
C++ 멤버함수, 가상함수 동작원리  (0) 2021.11.17
C++ 순수 가상함수, 추상 클래스  (0) 2021.11.11
C++ 업캐스팅, 오버라이딩, 가상함수  (0) 2021.11.08
반응형

 

멤버함수 동작원리

- C++의 객체의 멤버변수는 객체 내에 존재하지만 멤버함수는 다음과 같은 관계를 갖는다.

  • 멤버함수는 메모리의 한 공간에 별도로 위치한다.
  • 멤버함수가 정의된 클래스의 모든 객체가 이를 공유하는 형태를 취한다. (함수포인터를 생각하면 이해하기 편하다.)

 

 

 

 

가상함수 동작원리

- 예제 소스는 다음과 같다.

#include <iostream>
using namespace std;

class Parent
{
public:
    virtual void Func_1()
    {
        cout << "Parent : Func_1" << endl;
    }
    virtual void Func_2()
    {
        cout << "Parent : Func_2" << endl;
    }
};

class Son : public Parent
{
public:
    virtual void Func_1()
    {
        cout << "Son : Func_1" << endl;
    }
    void Func_3()
    {
        cout << "Son : Func_3" << endl;
    }
};

void main()
{
    Parent* parentPtr = new Parent();
    parentPtr->Func_1();
    
    Son* sonPtr = new Son();
    sonPtr->Func_1();
    
    //결과
    //Parent : Func_1
    //Son : Func_1
}

- 위의 코드에서 가상함수를 확인할 수 있는데, 한 개 이상의 가상함수를 포함하는 클래스에 대해서는 컴파일러가 '가상함수 테이블'이라는 것을 만든다. (V-Table이라고도 한다.)

- 가상함수 테이블은 Key와 Value를 가지고 있다.

  • Key : 호출하고자 하는 함수를 구분지어주는 구분자의 역할을 한다.
  • Value : 구분자에 해당하는 함수의 주소정보를 알려주는 역할을 한다.

- 따라서, Parent 클래스와 Son의 클래스의 가상함수 테이블은 다음과 같이 구성된다.

  • Parent 객체의 Func_1 함수를 호출하는 경우, Parent 테이블에서 첫 번쨰 행의 정보를 참조하여 Func_1 함수를 호출하게 된다.
  • Son 객체의 테이블을에서는 오버라이딩 된 가상함수의 Func_1에 대한 정보가 존재하지 않는다.
  • 즉, 오버라이딩 된 가상함수의 주소정보는 자식 클래스의 가상함수 테이블에 포함되지 않는다.
  • 결과적으로 오버라이딩된 가상함수를 호출하면, 가장 마지막에 오버라이딩을 한 자식 클래스의 멤버함수가 호출되게된다.

 

 

 

 

가상함수 테이블이 참조되는 방식

- 예제 소스가 실행되면, main함수가 호출되기 전에 가상함수 테이블이 메모리 공간에 할당된다.

  ※ 참고로 가상함수 테이블은 객체의 생성과 상관없이 메모리 공간에 할당된다. (가상함수 테이블이 멤버함수의 호출에 사용되는 일종의 데이터이기 때문.)

- main 함수가 호출되어 객체가 생성되고 나면, 각 Parent, Son 객체는 해당 클래스의 가상함수 테이블의 주소값이 저장된다.

  ※ 가상함수 테이블의 주소값은 우리가 직접 참조할수 있는 주소값이 아니고, 내부적 필요에 의해 참조되는 주소값이다.

- Parent 객체에서 Func_1함수를 호출하게되는 과정.

  • Parent 객체가 Parent 클래스의 가상함수 테이블 참조 → 100번지에 위치한 함수 실행

- Son 객체에서 Func_1함수를 호출하게 되는 과정.

  • Son객체가 Son 클래스의 가상함수 테이블 참조 → 200번지에 위치한 함수 실행

 

 

 

 

가상함수 테이블에 의한 속도의 저하

- 클래스에 가상함수가 포함되어 가상함수 테이블이 생성되면, 이 테이블을 참조하여 호출될 함수가 결정되기 때문에 실행속도가 감소하게된다.

- 하지만 극히 미미하고 속도차이를 감안하더라도 많은 장점을 제공하기 때문에 유용하게 활용되는것이다.

 

반응형

'Stack > C++' 카테고리의 다른 글

C++ friend  (0) 2021.12.05
C++ 다중상속  (0) 2021.11.22
C++ 순수 가상함수, 추상 클래스  (0) 2021.11.11
C++ 업캐스팅, 오버라이딩, 가상함수  (0) 2021.11.08
C++ 클래스 상속  (0) 2021.11.04
반응형

 

2018 LTS에서 2019 LTS로 넘어오면서 이상한게 눈에 띄었다.

위와 같이 한글로 주석해놓은게 유니티 인스펙터 창에서 미리보기할 때 깨져서 보이는것이었다.

간단하게 작업할때는 그냥 무시하고 사용했는데, 깃허브에 올리고 맥에서도 사용하려하니 장애가 많아서 결국 해결을 해야했다.

 

원인은 뻔했다. 파일이 UTF-8로 저장되어있지 않은것..

저장할 때마다 UTF-8로 변경해서 저장하면 되긴 한데, 매번 스크립트 생성할때마다 신경쓰기는 너무나 귀찮다.

해결법을 찾아보던 중, 스크립트 템플릿이 있는데 그 파일을 UTF-8로 변경해두변 된다고해서 해봤는데 어림없었다..

그 뒤, EditorConfig라는것을 찾아서 해결을 했다. 지금부터 설정법을 알아보자.

 

 

 

 

1. 기존 스크립트 변경법

- 이 부분은 노가다하는 수밖에 없다.

 

1-1) 스크립트를 연 뒤, 파일다른 이름으로 저장으로 저장을 시도한다.

1-2) 저장 옆에 화살표를 눌러 인코딩하여 저장을 선택한다.

1-3) 고급 저장 옵션창에서 인코딩란을 다음과 같이 설정한 다음 확인을 눌러 저장한다.

 

 

 

 

2. EditorConfig로 인코딩 설정하기

- EditorConfig : 프로젝트의 구성 파일 형식, 코딩 스타일을 정의하는 텍스트 편집기 플러그인(이라고 한다.)

 

2-1) 프로젝트안에 파일을 생성한 뒤, .editorconfig로 파일명을 설정해준다.

2-2) 생성한 파일을 메모장이나 VS로 연 뒤, 다음과 같이 작성해준다.

root = true

[*]
charset = utf-8

2-3) 저장을 하게되면 이후에 생성되는 스크립트는 UTF-8 인코딩으로 자동으로 설정된다.

 

※ 추가 설정법은 다음 사이트 참고

 

EditorConfig

What is EditorConfig? EditorConfig helps maintain consistent coding styles for multiple developers working on the same project across various editors and IDEs. The EditorConfig project consists of a file format for defining coding styles and a collection o

editorconfig.org

 

 

 

결과)

 

반응형
반응형

 

순수 가상함수(Pure Virtual Function)

- 함수의 몸체가 정의되지 않은 함수를 의미한다.

- 부모 클래스에서 사용하지 않는 함수이지만 자식 클래스는 무조건 동일한 이름으로 함수를 오버라이딩을 적용하게 강제하는 방법.

 

사용법

class A
{
public:
    virtual void Func1() = 0;
    virtual void Func2() = NULL;
    virtual void Func3() abstract;
};
  • 가상(virtual) 함수에 NULL(0) 값을 대입하거나 abstract를 붙여주면 해당 함수는 순수가상함수로 취급된다.
  • 순수 가상함수를 가진 클래스를 상속받은 클래스는 순수 가상함수의 몸체를 무조건 정의해주어야 한다.

 

 

추상 클래스(Abstract Class)

- 클래스 중에서는 객체생성을 목적으로 정의되지 않는 클래스도 존재한다.

- 멤버함수 중, 하나 이상 순수 가상함수로 선언하면 해당 클래스는 추상 클래스가 된다.

class B : public A
{
public:
    void Func1() override
    {
        cout << "Func1" << endl;
    }
    void Func2() override
    {
        cout << "Func2" << endl;
    }
    void Func3() override
    {
        cout << "Func3" << endl;
    }
};

void main()
{
    A a;	//컴파일 에러
    B b;
    b.Func1();
    b.Func2();
    b.Func3();
    
    //결과
    //Func1
    //Func2
    //Func3
}
  • A 클래스는 순수 가상함수를 포함하여 추상 클래스이기 때문에, 객체 생성시에 컴파일 에러가 발생한다.

 

 

반응형

'Stack > C++' 카테고리의 다른 글

C++ 다중상속  (0) 2021.11.22
C++ 멤버함수, 가상함수 동작원리  (0) 2021.11.17
C++ 업캐스팅, 오버라이딩, 가상함수  (0) 2021.11.08
C++ 클래스 상속  (0) 2021.11.04
C++ 함수 오버로딩, Deault 매개변수  (0) 2021.10.24

+ Recent posts