(c++) 클래스와 객체 1부

목차

1. 프로세스 지향과 객체 지향에 대한 사전 이해

2. 수업 소개

3. 클래스 정의

4. 클래스 접근 한정자와 캡슐화

5. 클래스 범위

6. 클래스 인스턴스화

7. 클래스 객체 크기 계산

8. 클래스 멤버 함수의 포인터


  • C 언어는 프로세스 지향적 이며 프로세스중점을 두고 문제 해결 단계를 분석하고 함수 호출을 통해 점진적으로 문제를 해결합니다.
  • C++ 객체지향을 기반으로 객체 에 초점을 맞추고 있으며 , 하나의 객체를 여러 객체로 분할하고 객체 간의 상호작용에 의존합니다. C++가 객체지향 언어를 기반으로 하는 이유 C++는 객체지향일 뿐만 아니라 프로세스지향도 가능하므로 하이브리드로 간주됩니다. 둘째, C++는 C 언어와 호환되어야 합니다.
지식이 부족함: Java는 순수한 객체 지향 언어입니다.

         C 언어 구조에서는 변수만 정의할 수 있지만, C++ 에서는 변수뿐만 아니라 함수도 구조 정의할 수 있습니다. 예를 들어 스택이 C 언어로 구현되면 구조체에는 변수만 정의할 수 있지만 , 이제 C++ 로 구현하면 구조체 에도 함수를 정의할 수 있습니다 .
  • c 언어 구현 스택:
성명:
#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int STDateType;

typedef struct Stack
{
	STDateType* arr;
	int top;
	int capacity;
}ST;

void StackInit(ST* ps);//初始化

void StackDestory(ST* ps);//销毁

void StackPush(ST* ps, STDateType x);//压栈

void StackPop(ST* ps);//出栈

STDateType StackTop(ST* ps);//取栈顶元素

bool StackEmpty(ST* ps);//判断栈是否为空

int StackSize(ST* ps);//获取栈元素个数

성취하다:
#include"Stack.h"

void StackInit(ST* ps)//初始化
{
	assert(ps);
	ps->arr = NULL;
	ps->top = 0;
	ps->capacity = 0;

}

void StackDestory(ST* ps)//销毁
{
	assert(ps);
	free(ps->arr);
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}

void StackPush(ST* ps, STDateType x)//压栈
{
	assert(ps);
	if (ps->top == ps->capacity) //扩容
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		STDateType* tmp = (STDateType*)realloc(ps->arr, sizeof(STDateType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc");
			exit(-1);
		}

		ps->arr = tmp;
		ps->capacity = newCapacity;
	}

	ps->arr[ps->top] = x;//尾插
	ps->top++;
}

void StackPop(ST* ps)//出栈
{
	assert(ps);
	assert(!StackEmpty(ps));
	ps->top--;
}

STDateType StackTop(ST* ps)//取栈顶元素
{
	assert(ps);
	assert(!StackEmpty(ps));//ps->top != 0
	
	return ps->arr[ps->top - 1];
}

bool StackEmpty(ST* ps)//判断栈是否为空
{
	assert(ps);

	return ps->top == 0;

}

int StackSize(ST* ps)//获取栈元素个数
{
	assert(ps);

	return ps->top;
}

  • C++ 구현 스택:
typedef int DataType;
struct Stack
{
   void Init(size_t capacity)
   {
      _array = (DataType*)malloc(sizeof(DataType) * capacity);
      if (nullptr == _array)
      {
         perror("malloc申请空间失败");
          return;
      }
      _capacity = capacity;
      _size = 0;
    }

    void Push(const DataType& data)
    {
        // 扩容
        _array[_size] = data;
        ++_size;
    }

    DataType Top()
    {
        return _array[_size - 1];
     }

     void Destroy()
     {
         if (_array)
         {
             free(_array);
             _array = nullptr;
             _capacity = 0;
             _size = 0;
         }
     }

     DataType* _array;
     size_t _capacity;
     size_t _size;
};

약간의 지식: 위 구조의 정의는 C++ 클래스 로 대체되는 것이 좋습니다.


class className
{
    // 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号
  • class 클래스를 정의하는 키워드이고 , ClassName 은 클래스 이름, {} 는 클래스의 본문이며, 클래스 정의 마지막에는 세미콜론을 생략할 수 없습니다 .

  • 클래스 본문에 있는 내용을 클래스의 멤버라고 합니다. 클래스에 있는 변수를 클래스의 속성 또는 멤버 변수 라고 합니다 . 클래스에 있는 함수를 클래스 의 메서드 또는 멤버 함수 라고 합니다.
클래스를 정의하는 방법에는 두 가지가 있습니다.
1. 모든 선언과 정의는 클래스 본문에 위치합니다. 참고: 멤버 함수가 클래스에 정의된 경우 컴파일러는 이를 인라인 함수 로 처리할 수 있습니다 .

2. 클래스 선언은 .h 파일에 위치하며, 멤버 함수 정의는 .cpp 파일에 위치합니다 . 참고: 클래스 이름은 멤버 함수 이름 앞에 추가해야 합니다.

지식이 거의 없음: 클래스 이름도 유형을 나타냅니다. 예:


4.1 접근 한정자
C++ 에서 캡슐화를 구현하는 방식: 클래스를 사용하여 객체의 속성과 메서드를 결합하여 객체를 더욱 완전하게 만들고 액세스 권한을 통해 선택합니다.
외부 사용자에게 선택적으로 인터페이스를 제공합니다 .

 

【접속 한정자 설명】
  • public 으로 수정된 멤버는 클래스 외부에서 직접 접근 가능

  • Protected 및 private 수정된 멤버는 클래스 외부에서 직접 액세스할 수 없습니다 ( 여기서 protected private은 유사합니다 ).

  • 액세스 범위는 이 액세스 한정자가 발생할 때 시작하고 다음 액세스 한정자가 발생할 때 끝납니다.

  • 나중에 액세스 한정자가 없으면 범위는 클래스의 끝인 }에서 끝납니다.

  • 클래스의 기본 접근 권한은 private 이고 struct는 public 입니다 ( struct는 C 와 호환되어야 하기 때문입니다 ).

참고: 액세스 한정자는 컴파일 타임에만 유용하며, 데이터가 메모리에 매핑되면 액세스 한정자에는 차이가 없습니다.

팁:

C++ 에서 구조체 클래스 의 차이점은 무엇입니까 ?
  •          C++는 C 언어 와 호환되어야 하므로 C++ struct를 구조체로 사용할 수 있습니다. 또한 C++ 구조체를 사용하여 클래스를 정의할 수도 있습니다. 클래스를 정의하는 클래스 와 동일하며 , struct 로 정의된 클래스의 기본 접근 권한은 public 이고, class로 정의된 클래스 의 기본 접근 권한 은 private이라는 점이 다릅니다 .
객체지향의 세 가지 주요 특징 : 캡슐화 , 상속, 다형성 .
클래스와 객체 단계에서는 클래스의 캡슐화 특성을 주로 연구하는데, 캡슐화란 무엇인가?
  • 캡슐화(Encapsulation): 데이터와 데이터를 조작하는 방법을 유기적으로 결합하고, 객체의 속성과 구현 세부 사항을 숨기고, 객체와 상호 작용할 수 있는 인터페이스만 노출합니다 .
  • 캡슐화는 본질적으로 사용자가 클래스를 더 쉽게 사용할 수 있도록 하는 일종의 관리입니다 . 예: 컴퓨터와 같은 복잡한 장치의 경우 사용자 전원 켜기/끄기 버튼, 키보드 입력, 모니터, USB 잭 등이며, 이를 통해 사용자는 컴퓨터와 상호 작용하고 일상 . 그러나 실제로 컴퓨터의 실제 작업은 CPU , 그래픽 카드, 메모리 및 기타 하드웨어 구성 요소입니다.
  • 컴퓨터 사용자의 경우 마더보드의 회로 배치, CPU 내부 설계 등 내부 핵심 구성 요소에 대해 걱정할 필요가 없습니다. 사용자는 컴퓨터를 켜는 방법과 방법만 알면 됩니다. 키보드와 마우스를 통해 컴퓨터와 상호 작용합니다 . 따라서 컴퓨터 제조업체는 공장을 떠날 때 내부 구현 세부 사항을 숨기기 위해 외부에 쉘을 배치하고 사용자가 컴퓨터와 상호 작용할 수 있도록 전원 스위치, 마우스 .
  • C ++ 언어 에서 캡슐화를 구현하기 위해서는 데이터를 연산하기 위한 데이터와 메소드를 클래스를 통해 유기적으로 결합할 수 있고, 접근 권한을 이용해 객체의 내부 구현 내용을 숨기고 클래스 외부에서 직접 어떤 메소드를 사용할 수 있는지 제어할 수 있다 .

클래스는 새로운 범위를 정의하며 , 클래스의 모든 멤버는 클래스의 범위 내에 있습니다 . 클래스 외부에서 멤버를 정의할 때 :: 범위 연산자를 사용하여 해당 멤버가 속한 클래스 범위를 나타내야 합니다.
class Person
{
public:
     void PrintPersonInfo();
private:
  char _name[20];
  char _gender[3];
  int  _age;
};

// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
   cout << _name << " "<< _gender << " " << _age << endl;
}


클래스 유형에서 객체를 생성하는 프로세스를 클래스 인스턴스화라고 합니다.
1. 클래스는 객체를 설명합니다 . 모델 과 비슷합니다 . 클래스의 멤버를 제한합니다. 클래스를 정의해도 클래스 를 저장하기 위한 실제 메모리 공간이 할당 되지 않습니다 .
2. 클래스는 여러 객체를 인스턴스화할 수 있으며, 인스턴스화된 객체는 실제 물리적 공간을 차지하고 클래스 멤버 변수를 저장합니다 .
3. 비유를 해보세요. 클래스에서 개체를 인스턴스화하는 것은 건축 설계 도면을 사용하여 현실에서 집을 짓는 것과 같습니다. 클래스는 설계 도면과 같습니다 . 필요한 것만 설계하고 실제 건물은 없습니다. 마찬가지로 클래스는 설계일 뿐입니다. 객체는 실제로 데이터를 저장하고 물리적 공간을 차지할 수 있습니다.


     7.1 클래스 객체의 저장 방식 추측하기
  • 객체에는 클래스의 다양한 멤버가 포함되어 있습니다.

결함: 각 객체의 멤버변수는 다르지만 동일한 함수가 호출된다.
클래스가 여러 객체를 생성하면 각 객체에 코드 복사본이 저장되며, 동일한 코드가 여러 번 저장되므로 공간이 낭비됩니다.

  • 코드 사본은 1개만 저장되며, 코드가 저장된 주소가 객체에 저장됩니다.

  • 멤버 변수만 저장되며, 멤버 함수는 공개 코드 섹션에 저장됩니다.
                

 

 컴파일러는 일반적으로 세 번째 저장 방법인 테스트를 채택합니다.

7.2 학급 규모

클래스의 크기는 실제로 클래스에 있는 " 멤버 변수 " 의 합입니다. 멤버 함수 클래스에 들어가지 않으므로 클래스 공간의 크기를 차지하지 않습니다. 멤버 변수는 메모리 정렬 규칙을 따릅니다. 또한, 빈 클래스의 크기에 주의하십시오. 빈 클래스는 특별합니다. 컴파일러는 이 클래스의 객체를 고유하게 식별하기 위해 빈 클래스에 바이트를 제공합니다.

 메모리 정렬에 관하여:

1. 첫 번째 멤버는 구조에서 주소 오프셋 0 에 있습니다.
2. 다른 멤버 변수는 특정 숫자(정렬 번호)의 정수배인 주소에 정렬되어야 합니다.
참고: 정렬 번호 = 컴파일러의 기본 정렬 번호와 멤버 크기 중 더 작은 것입니다.
VS 의 기본 정렬 수는 8 입니다.
3. 구조의 전체 크기는 최대 정렬 수(모든 변수 유형 중 가장 큰 값과 가장 작은 기본 정렬 매개변수)의 정수 배수입니다.
4. 구조가 중첩되고 중첩된 구조가 자체 최대 정렬 번호의 정수 배수로 정렬되는 경우 구조의 전체 크기는 모든 최대 정렬 번호(중첩 구조의 정렬 번호 포함)를 곱한 정수입니다.

구조 메모리 정렬 도 참조하세요 .


class Date
{
public:
	void Init(int year, int month, int day)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}
	void Print()
	{
		cout << _year << "." << _month << "." << _day << endl;
	}

private:
	int _year;  //声明
	int _month;
	int _day;
};

int main()
{
	Date d1, d2;

	d1.Init(2023, 9, 1);
	d1.Print();

	d2.Init(2023, 9, 2);
	d2.Print();
	return 0;
}

위 클래스에는 다음과 같은 문제가 있습니다.
Date 클래스 에는 두 개의 멤버 함수 Init Print가 있습니다 . 함수 본문에는 서로 다른 객체 간에 구별이 없습니다. 따라서 d1이 Init 함수를 호출 할 때 함수는 함수 대신 d1 객체를 설정해야 한다는 것을 어떻게 알 수 있습니까? d2 객체?

C++는 this 포인터를 도입하여 이 문제를 해결합니다 . 즉, C++ 컴파일러는 각 " 비정적 멤버 함수 " 에 숨겨진 포인터 매개 변수를 추가하여 포인터가 현재 객체 ( 함수가 호출될 때 함수를 호출하는 객체) 를 가리킬 수 있도록 합니다. is running ) 함수 본문의 "멤버 변수" 이 포인터를 통해 액세스됩니다. 모든 작업은 사용자에게 투명합니다. 즉, 사용자가 이를 전달할 필요가 없으며 컴파일러가 자동으로 완료합니다 .

 이 포인터 의 특징
  •  포인터의 유형: 클래스 유형 * const , 즉 멤버 함수에서 포인터에는 값을 할당할 수 없습니다.
  •  " 멤버 함수 " 내 에서만 사용할 수 있습니다.
  • this 포인터는 본질적으로 " 멤버 함수 " 의 형식 매개변수 입니다 . 개체가 멤버 함수를 호출하면 개체 주소가 실제 매개변수로 this 매개변수에 전달됩니다. 따라서 this 포인터는 객체에 저장되지 않습니다 .
  • this 포인터는 " 멤버 함수 " 의 첫 번째 암시적 포인터 매개변수 입니다 . 일반적으로 컴파일러에 의해 ecx 레지스터를 통해 자동으로 전달 사용자가 전달할 필요가 없습니다.
예:
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void Print()
	{
		cout << this << endl;
		cout << "Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();  
	return 0;
}

답: 함수가 공개 코드 영역에 있기 때문에 정상적으로 실행되는데, 포인터가 이 함수를 호출하더라도 포인터가 디코딩되지 않습니다.

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
		//cout << this->_a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->PrintA();   
	return 0;
}

답변: 널 포인터 문제로 인해 실행이 중단되었습니다. 널 포인터가 역참조되었습니다.

이 포인터의 저장 위치는 어디입니까?
  • 이 포인터는 형식 매개변수이고 형식 매개변수는 일반적으로 스택 영역에 저장되기 때문에 이것의 저장 위치는 스택 영역입니다.
  • 하지만 이 포인터는 최적화될 수도 있습니다. vs는 레지스터에 저장되므로 특정 저장 위치는 컴파일러에 따라 다릅니다.

참고: 개념적 콘텐츠는 Bittech에서 제공됩니다.

추천

출처blog.csdn.net/m0_73969113/article/details/132476178