> 백엔드 개발 > 파이썬 튜토리얼 > C 프로그래머를 위한 Python의 OOP 개념 98

C 프로그래머를 위한 Python의 OOP 개념 98

Mary-Kate Olsen
풀어 주다: 2024-11-16 15:50:03
원래의
482명이 탐색했습니다.

Conceitos de POO em Python para Programadores C  98

다음은 C 98 프로그래머를 위한 Python의 OOP 개념에 대한 포괄적인 데모입니다.

클래스 정의 및 객체 생성

파이썬

# Privado por convenção: _underscore_simples
# "Realmente privado": __underscore_duplo (name mangling)
# Público: sem underscore

from abc import abstractmethod
class Animal(ABC):
    # Em python, variáveis declaradas no escopo da classe e não dentro de um
    # método específico, são automaticamente compartilhadas por todas instâncias.
    species_count = 0 # além disso, elas podem ser inicializadas diretamente dentro da classe.

    # Construtor
    def __init__(self, name):
        # Variáveis de instância
        self.name = name       # público
        self._age = 0          # protegido por convenção
        self.__id = id(self)   # privado (mas você consegue acessar com name mangling)
        Animal.species_count += 1

    # Destrutor
    def __del__(self):
        Animal.species_count -= 1

    # Método regular
    @abstractmethod
    def make_sound(self):
        pass  # Equivalente a um método abstrato/virtual (deve ser implementado apenas nas classes filhas)

    # Método estático (não precisa da instância para ser utilizado, nem utiliza seus atributos)
    @staticmethod
    def get_kingdom():
        return "Animalia"

    # Método de classe (recebe a classe como primeiro argumento, pode acessar atributos da classe)
    @classmethod
    def get_species_count(cls):
        return cls.species_count

    # Decorador de propriedade (getter)
    @property
    def age(self):
        return self._age

    # Decorador de propriedade (setter)
    @age.setter
    def age(self, value):
        if value >= 0:
            self._age = value

    # Métodos especiais (sobrecarga de operadores)
    def __str__(self):                # Como toString() - para string legível
        return f"Animal named {self.name}"

    def __repr__(self):               # Para debugging
        return f"Animal(name='{self.name}')"

    def __eq__(self, other):          # Operador de comparação ==
        return isinstance(other, Animal) and self.name == other.name

    def __len__(self):                # Função len()
        return self._age

    def __getitem__(self, key):       # Operador de acesso []
        if key == 'name':
            return self.name
        raise KeyError(key)
로그인 후 복사
로그인 후 복사

C98

#include <iostream>
#include <string>
#include <sstream>

class Animal {
public:
    static int species_count;

    Animal(const std::string& name) : name(name), _age(0), __id(++id_counter) { // construtor
        ++species_count;
    }

    ~Animal() {    // destrutor
        --species_count;
    }

    virtual void make_sound() = 0; // Método não implementável na classe base (virtual/abstrato)

    static std::string get_kingdom() {  // Não existe distinção entre
    //  @classmethod e @staticmethod em cpp, apenas static methods.
        return "Animalia";
    }

    // static methods podem ser utilizados sem instanciar uma classe e têm
    // acesso às propriedades estáticas da classe:
    static int get_species_count() {
        return species_count;
    }

    // getter:
    int get_age() const {
        return _age;
    }

    // setter:
    void set_age(int age) {
        if (age >= 0) {
            _age = age;
        }
    }

    // Implementação dos métodos especiais que vimos em python:
    std::string to_string() const {
        return "Animal named " + name;
    }

    std::string repr() const {
        std::ostringstream oss;
        oss << "Animal(name='" << name << "', age=" << _age << ",>



<h2>
  
  
  Herança
</h2>

<h3>
  
  
  Python
</h3>



<pre class="brush:php;toolbar:false">class Dog(Animal):
    def __init__(self, name, breed):
        # Chama o construtor da classe pai
        super().__init__(name)
        self.breed = breed

    # Sobrescreve o método da classe pai
    def make_sound(self):
        return "Woof!"
로그인 후 복사
로그인 후 복사

C98

class Dog : public Animal {
public:
    Dog(const std::string& name, const std::string& breed) : Animal(name), breed(breed) {}

    void make_sound() override {
        std::cout << "Woof!" << std::endl;
    }

private:
    std::string breed;
};
로그인 후 복사
로그인 후 복사

다중 상속

파이썬

class Pet:
    def is_vaccinated(self):
        return True

class DomesticDog(Dog, Pet):
    pass
로그인 후 복사
로그인 후 복사

C98

class Pet {
public:
    bool is_vaccinated() const {
        return true;
    }
};

class DomesticDog : public Dog, public Pet {
public:
    DomesticDog(const std::string& name, const std::string& breed) : Dog(name, breed) {}
};
로그인 후 복사
로그인 후 복사

추상 클래스

파이썬

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass
로그인 후 복사
로그인 후 복사

C98

class Shape {
public:
    virtual ~Shape() {}
    virtual double area() const = 0;
};
로그인 후 복사
로그인 후 복사

사용예

파이썬

if __name__ == "__main__":
    # Cria objetos
    dog = Dog("Rex", "Golden Retriever")

    # Acessa atributos
    print(dog.name)          # Público
    print(dog._age)         # Protegido (ainda acessível)
    # print(dog.__id)       # Isso falhará 
    print(dog._Animal__id)  # Isso funciona (acessando attribute privado com name mangling)

    # Propriedades
    dog.age = 5             # Usa setter automaticamente
    print(dog.age)          # Usa getter automaticamente

    # Métodos estáticos e de classe
    print(Animal.get_kingdom())
    print(Animal.get_species_count())

    # Verifica herança
    print(isinstance(dog, Animal))  # True
    print(issubclass(Dog, Animal)) # True

    # Métodos especiais em ação
    print(str(dog))        # Usa __str__
    print(repr(dog))       # Usa __repr__
    print(len(dog))        # Usa __len__
    print(dog['name'])     # Usa __getitem__
로그인 후 복사
로그인 후 복사

C98

int main() {
    // Cria objetos
    Dog dog("Rex", "Golden Retriever");

    // Acessa atributos
    std::cout << dog.name << std::endl;          // Público
    std::cout << dog.get_age() << std::endl;     // Protegido (ainda acessível)
    // std::cout << dog.__id << std::endl;       // Isso falhará (privado)

    // Propriedades
    dog.set_age(5);             // Usa setter
    std::cout << dog.get_age() << std::endl;     // Usa getter

    // Métodos estáticos e de classe
    std::cout << Animal::get_kingdom() << std::endl;
    std::cout << Animal::get_species_count() << std::endl;

    // Equivalente aos "métodos especiais":

    // Verifica herança
    if (dog.isinstance<Animal>()) {
        std::cout << "dog é uma instância de Animal" << std::endl;
    }

    std::cout << dog.to_string() << std::endl;   // Usa to_string
    std::cout << dog.repr() << std::endl;        // Usa repr
    std::cout << dog["name"] << std::endl;       // Usa operador []
}
로그인 후 복사
로그인 후 복사

Python과 C 98의 주요 차이점

  1. 공개/비공개/보호 키워드 없음(명명 규칙 사용)
  2. 다중 상속은 다릅니다.
    • Python은 C3 선형화와 함께 MRO(Method Resolution Order)를 사용합니다
    • C와 같은 가상 상속이 필요하지 않습니다
    • super()는 자동으로 MRO를 따릅니다
    • Python에서는 기본 클래스의 순서가 중요합니다
    • __mro__를 사용하여 해결 순서를 검사할 수 있습니다.
  3. 모든 방법은 기본적으로 가상입니다
  4. 포인터/참조 사이에는 구분이 없습니다
  5. 메모리 관리 불필요(가비지 컬렉터)
  6. 정적 타이핑 대신 동적 타이핑
  7. getter/setter 메소드 대신 속성 데코레이터
  8. 특수 메서드는 연산자
  9. 키워드 대신 __name__ 형식을 사용합니다.
  10. 연산자 오버로드를 위한 추가 Python 구문(예: __eq__ 대 연산자==)

객체의 모든 속성과 메소드를 보려면 dir(object)를 사용하고 문서화를 위해서는 help(object)를 사용하세요.

특별 주제:

다이아몬드 상속 문제

                              Animal

                           .    '    ,
                             _______
                        _  .`_|___|_`.  _
                    Pet     \ \   / /     WorkingAnimal
                             \ ' ' /
                              \ " /   
                               \./

                           DomesticDog
로그인 후 복사

C 98의 다이아몬드 상속 문제

다이아몬드 상속은 클래스가 두 클래스에서 상속되고 두 클래스가 공통 기본 클래스에서 상속될 때 발생합니다. 이로 인해 여러 가지 문제가 발생할 수 있습니다.

  1. 모호성: 공통 기본 클래스의 메서드와 속성이 모호해질 수 있습니다.
  2. 데이터 중복: 각 파생 클래스는 공통 기본 클래스 멤버의 자체 복사본을 가질 수 있으므로 데이터 중복이 발생합니다.

C 98의 다이아몬드 상속의 예

class Animal {
public:
    Animal() {
        std::cout << "Animal constructor" << std::endl;
    }
    virtual void make_sound() {
        std::cout << "Some generic animal sound" << std::endl;
    }
};

class Pet : public Animal {
public:
    Pet() : Animal() {
        std::cout << "Pet constructor" << std::endl;
    }
    void make_sound() override {
        std::cout << "Pet sound" << std::endl;
    }
};

class WorkingAnimal : public Animal {
public:
    WorkingAnimal() : Animal() {
        std::cout << "WorkingAnimal constructor" << std::endl;
    }
    void make_sound() override {
        std::cout << "Working animal sound" << std::endl;
    }
};

class DomesticDog : public Pet, public WorkingAnimal {
public:
    DomesticDog() : Animal(), Pet(), WorkingAnimal() {
        std::cout << "DomesticDog constructor" << std::endl;
    }
    void make_sound() override {
        Pet::make_sound();  // Ou WorkingAnimal::make_sound(), dependendo do comportamento desejado
    }
};

int main() {
    DomesticDog dog;
    dog.make_sound();
    return 0;
}
로그인 후 복사

예상되는 동작

Animal constructor
Pet constructor
WorkingAnimal constructor
DomesticDog constructor
Pet sound
로그인 후 복사

이 예에서 DomesticDog는 Pet과 WorkingAnimal을 상속하며 둘 다 Animal을 상속합니다. 이로써 가보 다이아몬드가 탄생합니다. 가상 상속은 데이터 중복과 모호성을 피하기 위해 사용됩니다.

Python이 다이아몬드 상속을 자동으로 방지하는 방법

Python은 C3 선형화와 함께 MRO(Method Resolution Order)를 사용하여 다이아몬드 상속 문제를 자동으로 해결합니다. MRO는 메소드나 속성을 찾을 때 클래스를 확인하는 순서를 결정합니다.

Python의 다이아몬드 상속 예

# Privado por convenção: _underscore_simples
# "Realmente privado": __underscore_duplo (name mangling)
# Público: sem underscore

from abc import abstractmethod
class Animal(ABC):
    # Em python, variáveis declaradas no escopo da classe e não dentro de um
    # método específico, são automaticamente compartilhadas por todas instâncias.
    species_count = 0 # além disso, elas podem ser inicializadas diretamente dentro da classe.

    # Construtor
    def __init__(self, name):
        # Variáveis de instância
        self.name = name       # público
        self._age = 0          # protegido por convenção
        self.__id = id(self)   # privado (mas você consegue acessar com name mangling)
        Animal.species_count += 1

    # Destrutor
    def __del__(self):
        Animal.species_count -= 1

    # Método regular
    @abstractmethod
    def make_sound(self):
        pass  # Equivalente a um método abstrato/virtual (deve ser implementado apenas nas classes filhas)

    # Método estático (não precisa da instância para ser utilizado, nem utiliza seus atributos)
    @staticmethod
    def get_kingdom():
        return "Animalia"

    # Método de classe (recebe a classe como primeiro argumento, pode acessar atributos da classe)
    @classmethod
    def get_species_count(cls):
        return cls.species_count

    # Decorador de propriedade (getter)
    @property
    def age(self):
        return self._age

    # Decorador de propriedade (setter)
    @age.setter
    def age(self, value):
        if value >= 0:
            self._age = value

    # Métodos especiais (sobrecarga de operadores)
    def __str__(self):                # Como toString() - para string legível
        return f"Animal named {self.name}"

    def __repr__(self):               # Para debugging
        return f"Animal(name='{self.name}')"

    def __eq__(self, other):          # Operador de comparação ==
        return isinstance(other, Animal) and self.name == other.name

    def __len__(self):                # Função len()
        return self._age

    def __getitem__(self, key):       # Operador de acesso []
        if key == 'name':
            return self.name
        raise KeyError(key)
로그인 후 복사
로그인 후 복사

예상되는 동작

#include <iostream>
#include <string>
#include <sstream>

class Animal {
public:
    static int species_count;

    Animal(const std::string& name) : name(name), _age(0), __id(++id_counter) { // construtor
        ++species_count;
    }

    ~Animal() {    // destrutor
        --species_count;
    }

    virtual void make_sound() = 0; // Método não implementável na classe base (virtual/abstrato)

    static std::string get_kingdom() {  // Não existe distinção entre
    //  @classmethod e @staticmethod em cpp, apenas static methods.
        return "Animalia";
    }

    // static methods podem ser utilizados sem instanciar uma classe e têm
    // acesso às propriedades estáticas da classe:
    static int get_species_count() {
        return species_count;
    }

    // getter:
    int get_age() const {
        return _age;
    }

    // setter:
    void set_age(int age) {
        if (age >= 0) {
            _age = age;
        }
    }

    // Implementação dos métodos especiais que vimos em python:
    std::string to_string() const {
        return "Animal named " + name;
    }

    std::string repr() const {
        std::ostringstream oss;
        oss << "Animal(name='" << name << "', age=" << _age << ",>



<h2>
  
  
  Herança
</h2>

<h3>
  
  
  Python
</h3>



<pre class="brush:php;toolbar:false">class Dog(Animal):
    def __init__(self, name, breed):
        # Chama o construtor da classe pai
        super().__init__(name)
        self.breed = breed

    # Sobrescreve o método da classe pai
    def make_sound(self):
        return "Woof!"
로그인 후 복사
로그인 후 복사

이 예에서 Python은 MRO를 사용하여 다이아몬드 상속을 자동으로 해결합니다. __mro__:
속성을 ​​사용하여 MRO를 확인할 수 있습니다.

class Dog : public Animal {
public:
    Dog(const std::string& name, const std::string& breed) : Animal(name), breed(breed) {}

    void make_sound() override {
        std::cout << "Woof!" << std::endl;
    }

private:
    std::string breed;
};
로그인 후 복사
로그인 후 복사

Python의 MRO는 DomesticDog가 Pet 및 WorkingAnimal에서 올바르게 상속되고 Animal이 객체보다 먼저 해결되도록 보장합니다. 따라서 선언 순서는 MRO에 영향을 주지만 C3 선형화는 계층 구조가 존중되도록 보장합니다.

설명:

  1. 선언 순서: MRO는 가장 많이 파생된 클래스부터 시작하여 기본 클래스가 선언된 순서를 따릅니다.
  2. C3 선형화: 각 클래스가 슈퍼클래스 앞에 나타나도록 하고 상속 순서가 유지되도록 합니다.

데이터 구조: 스택, 큐, 맵

스택

파이썬

class Pet:
    def is_vaccinated(self):
        return True

class DomesticDog(Dog, Pet):
    pass
로그인 후 복사
로그인 후 복사

C98

class Pet {
public:
    bool is_vaccinated() const {
        return true;
    }
};

class DomesticDog : public Dog, public Pet {
public:
    DomesticDog(const std::string& name, const std::string& breed) : Dog(name, breed) {}
};
로그인 후 복사
로그인 후 복사

대기줄

파이썬

from abc import ABC, abstractmethod

class Shape(ABC):
    @abstractmethod
    def area(self):
        pass
로그인 후 복사
로그인 후 복사

C98

class Shape {
public:
    virtual ~Shape() {}
    virtual double area() const = 0;
};
로그인 후 복사
로그인 후 복사

지도

파이썬

if __name__ == "__main__":
    # Cria objetos
    dog = Dog("Rex", "Golden Retriever")

    # Acessa atributos
    print(dog.name)          # Público
    print(dog._age)         # Protegido (ainda acessível)
    # print(dog.__id)       # Isso falhará 
    print(dog._Animal__id)  # Isso funciona (acessando attribute privado com name mangling)

    # Propriedades
    dog.age = 5             # Usa setter automaticamente
    print(dog.age)          # Usa getter automaticamente

    # Métodos estáticos e de classe
    print(Animal.get_kingdom())
    print(Animal.get_species_count())

    # Verifica herança
    print(isinstance(dog, Animal))  # True
    print(issubclass(Dog, Animal)) # True

    # Métodos especiais em ação
    print(str(dog))        # Usa __str__
    print(repr(dog))       # Usa __repr__
    print(len(dog))        # Usa __len__
    print(dog['name'])     # Usa __getitem__
로그인 후 복사
로그인 후 복사

C98

int main() {
    // Cria objetos
    Dog dog("Rex", "Golden Retriever");

    // Acessa atributos
    std::cout << dog.name << std::endl;          // Público
    std::cout << dog.get_age() << std::endl;     // Protegido (ainda acessível)
    // std::cout << dog.__id << std::endl;       // Isso falhará (privado)

    // Propriedades
    dog.set_age(5);             // Usa setter
    std::cout << dog.get_age() << std::endl;     // Usa getter

    // Métodos estáticos e de classe
    std::cout << Animal::get_kingdom() << std::endl;
    std::cout << Animal::get_species_count() << std::endl;

    // Equivalente aos "métodos especiais":

    // Verifica herança
    if (dog.isinstance<Animal>()) {
        std::cout << "dog é uma instância de Animal" << std::endl;
    }

    std::cout << dog.to_string() << std::endl;   // Usa to_string
    std::cout << dog.repr() << std::endl;        // Usa repr
    std::cout << dog["name"] << std::endl;       // Usa operador []
}
로그인 후 복사
로그인 후 복사

Python 및 C 98의 OOP 개념에 대한 이 가이드를 따라주셔서 감사합니다. 이 가이드가 귀하의 학습 여정에 도움이 되기를 바랍니다. 콘텐츠가 마음에 드셨다면 댓글을 남겨주시고, 좋아요를 눌러주시고 친구, 동료들과 공유해 주세요. 오류 발견시 댓글 남겨주시면 수정하겠습니다! 다음 시간까지!

위 내용은 C 프로그래머를 위한 Python의 OOP 개념 98의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:dev.to
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
저자별 최신 기사
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿