산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Industrial programming >> C 언어

C++ 가상 함수 마스터: 개념, 예제, override 키워드

C++ 가상 함수

이 튜토리얼에서는 C++ 가상 함수의 목적과 실전 활용법을 코드 예제와 함께 설명합니다.

소개

가상 함수는 파생 클래스에서 오버라이드될 것으로 예상되는 기반 클래스 멤버입니다. 함수를 가상으로 선언하면 기반 클래스 포인터나 참조로 접근하더라도 가장 파생된 구현이 호출되도록 보장합니다.

기반 클래스에 non-virtual 멤버가 포함된 경우, 실제 객체 타입에 관계없이 기반 포인터로 해당 멤버를 호출하면 항상 기반 버전이 실행됩니다. 다음을 고려해 보세요:

class Base {
public:
    void print() {
        // 기반 구현
    }
};
class Derived : public Base {
public:
    void print() {
        // 파생 구현
    }
};

아래 프로그램에서 Base*가 Derived 인스턴스를 가리키지만 print()는 기반 버전으로 해석됩니다:

int main() {
    Derived derived1;
    Base* base1 = &derived1;
    base1->print(); // Base::print() 호출
    return 0;
}

다형적 동작을 얻으려면 기반 클래스에서 함수를 virtual로 선언하세요:

class Base {
public:
    virtual void print() {
        // 기반 구현
    }
};

가상 함수는 C++ 다형성의 핵심입니다. 더 깊이 알아보려면 C++ 다형성 가이드를 참조하세요.


예제 1: 기본 가상 함수 사용

#include <iostream>
using namespace std;

class Base {
public:
    virtual void print() {
        cout << "Base Function" << endl;
    }
};

class Derived : public Base {
public:
    void print() override {
        cout << "Derived Function" << endl;
    }
};

int main() {
    Derived derived1;
    Base* base1 = &derived1;
    base1->print(); // Derived Function 출력
    return 0;
}

출력

Derived Function

Base::print가 virtual이므로 기반 포인터를 통해서도 Derived::print로 디스패치됩니다.

C++ 가상 함수 마스터: 개념, 예제, override 키워드

C++ override 식별자

C++11부터 override 키워드는 함수가 가상 기반 멤버를 진정으로 오버라이드하는지 컴파일러가 검증하도록 강제해 실수로 잘못된 오버라이딩을 방지합니다.

예제:

class Base {
public:
    virtual void print() {
        // 기반 구현
    }
};
class Derived : public Base {
public:
    void print() override {
        // 파생 구현
    }
};

오버라이딩 함수를 클래스 외부에서 정의할 때는:

class Derived : public Base {
public:
    void print() override; // 선언
};
void Derived::print() {
    // 구현
}

override 안전하게 사용하기

override가 없으면 오타나 시그니처 불일치가 조용히 새 함수를 생성해 오버라이딩이 아닌 결과를 낳으며 미묘한 버그를 유발합니다. 컴파일러가 즉시 오류를 내므로 문제를 바로 발견할 수 있습니다. 흔한 실수로는:


가상 함수의 실전 활용

Animal 기반 클래스와 파생 Dog, Cat 클래스를 고려해 보세요. 각 클래스는 생성자로 초기화되는 type 멤버를 가집니다.

class Animal {
private:
    string type;
public:
    Animal() : type("Animal") {}
    virtual string getType() const {
        return type;
    }
};
class Dog : public Animal {
private:
    string type;
public:
    Dog() : type("Dog") {}
    string getType() const override {
        return type;
    }
};
class Cat : public Animal {
private:
    string type;
public:
    Cat() : type("Cat") {}
    string getType() const override {
        return type;
    }
};

getType()이 virtual이므로 단일 헬퍼로 모든 동물을 출력할 수 있습니다:

void print(Animal* ani) {
    cout << "Animal: " << ani->getType() << endl;
}

main()에서의 사용:

int main() {
    Animal* animal1 = new Animal();
    Animal* dog1 = new Dog();
    Animal* cat1 = new Cat();
    print(animal1);
    print(dog1);
    print(cat1);
    delete animal1;
    delete dog1;
    delete cat1;
    return 0;
}

출력

Animal: Animal
Animal: Dog
Animal: Cat

getType()을 가상으로 만들어 각 파생 클래스에 print() 로직을 중복하지 않고도 올바른 type에 접근할 수 있습니다.

C 언어

  1. C++ 배열을 함수에 전달하는 방법: 실전 가이드
  2. C++ 클래스와 객체: 객체지향 프로그래밍 실전 가이드
  3. C++ 프렌드 함수와 프렌드 클래스: 접근 제어 마스터하기
  4. C++ 클래스 템플릿 마스터: 실전 가이드
  5. C++ 함수 완전 정복: 실전 코드 예제로 이해하기
  6. Verilog 함수 마스터하기: 효율적인 RTL 설계를 위한 활용법
  7. C 함수 마스터: 선언, 정의, 호출, 인자 전달(값/참조), 재귀
  8. C++ 저장 클래스 완벽 가이드: 범위, 수명, 용법
  9. C++ 오버로딩 마스터하기: 함수 & 연산자 오버로딩 완전 정복
  10. C++ 다형성 이해하기: virtual 함수와 순수 가상 함수