728x90
728x90
MSDN 문서 4단계인 ASP.NET Core MVC 앱에 모델 추가 단계에서 생긴 문제들

● 도구 -Nuget 패키지 관리자 - 패키지 관리자 콘솔에서 Install-Package Microsoft.EntityFrameworkCore.SqlServer 실행하자 오류

 

● Microsoft.EntityFrameworkCore.SqlServer 패키지를 찾을 수 없습니다

 

● Install-Package : NU1202: Microsoft.EntityFrameworkCore.SqlServer 6.0.1 패키지가 netcoreapp3.1(.NETCoreApp,Version=v3.1)과(와) 호환되지 않습니다. Microsoft.EntityFrameworkCore.SqlServer 6.0.1 패키지는 다음을 지원합니다. net6.0(.NETCoreApp,Version=v6.0)

 

get-help  NuGet을 명령하면 도움말을 얻을 수 있다. 
NuGet은 .NET 프로젝트에 라이브러리 및 도구를 추가하는 통합 패키지 관리 도구.

NuGet NuGet 패키지 관리자 명령 (cmdlet)

 

 

시행한 것 (확실한 근거 없는 것도 있음)

도구 - Nuget 패키지 관리자 - 패키지 관리자 설정 - 일반 에서 캐시 지우기
기본 패키지 관리 형식 : PackageReference로 선택 (지금 하는 프로젝트는 종속성이 있음)

 


● dotnet tool 확인할 수 없습니다.(error NU1100: NU1101:) -> dotnet 6.0 설치 (https://devscb.tistory.com/62)

\AppData\Roaming\NuGet 에서 NuGet.Config 삭제

아래 순서대로 Nuget 패키지 관리자 콘솔에 입력

Install-Package Microsoft.NETCore.DotNetAppHost -Version 3.1.1

 

아래는 개발하는 것에 따라 다른가? ... 다음거 따라하다보니 DbContextOptionsBuilder does not contain a definition for 'usesqlserver' and no extension method 'usesqlserver' 가 나와서 둘 중 아래 걸로 다시 깔음. MSDN 예제는 SqlServer가 들어가기도 해서 다시 설치함.

Install-Package Microsoft.EntityFrameworkCore -Version 3.1.10
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 3.1.10

* 참고 : Install-Package Microsoft.EntityFrameworkCore.SqlServer 으로 버전이 없으면 최신으로 복구해버리는데 지금 NetCore 3.1버전으로 하고 있으니 버전을 지정해서 설치해야 오류가 없다.

 

 

수정) 개발하다보니 컨트롤러에 스캐폴드 추가가 안되는데 그 메세지가 다음과 같았음

1) Nuget 패키지 복원에 실패했습니다. 패키지 변경 사항을 롤백하십시오

 

2) 프로젝트를 빌드하지 못했습니다. 
그 이유가 버전호환이 안된다 해서 도구 - Nuget 패키지 관리자 - 패키지 관리자 설정 - 일반에서 캐시 지우기캐시 지우고 다시 3.1.21 버전으로 깔음. 그리고 프로젝트 다시 빌드 해 주니 스캐폴드 추가가 잘 됨.

Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 3.1.21

 

그 과정에서 Microsoft.EntityFrameworkCore.SqlServer가 아닌 Microsoft.EntityFrameworkCore 3.1.10이 잘못 깔려있어서 지워줌. 도구 - Nuget 패키지 관리자 - 패키지 관리자 콘솔에서 Get-Package 명령하면 볼 수 있음.

 

지운 후 지금 상태.

  

 

 

완료.

 

 

 

참고

https://docs.microsoft.com/ko-kr/nuget/consume-packages/package-restore-troubleshooting

https://docs.microsoft.com/ko-kr/nuget/release-notes/known-issues

https://docs.microsoft.com/ko-kr/nuget/consume-packages/package-restore#restore-packages-manually-using-visual-studio

https://note.heyo.me/dotnet-tool-%ED%99%95%EC%9D%B8%ED%95%A0-%EC%88%98-%EC%97%86%EC%8A%B5%EB%8B%88%EB%8B%A4-error-nu1100/

https://www.nuget.org/packages/Microsoft.NETCore.DotNetAppHost/3.1.1

https://www.nuget.org/packages/Microsoft.EntityFrameworkCore/3.1.10

https://okky.kr/article/878182?note=2248788 

 

 

 

windows에 깔린 dotnet 버전 확인하기 (cmd 창에서 확인)
C:\Users\PC 이름>dotnet --list-sdks

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
IPython 설치, 실행

 

 

pip install ipython
ipython

 

 

 

버전 업그레이드

pip install --upgrade pip

 

 

 

Git Bash를 이용한 파이썬 코드 실행

Git Bash 종료 후 앞서 클론한 첫 번째 예제 폴더가 들어있는 곳에서
마우스 우측 버튼을 눌러 Git Bash Here을 실행한다.

 

 

아래 명령어를 실행한다. 폴더가 생겨났다.
1천건의 샘플 정보를 만들어내는 작업이었다. 
...라는데 안되서 찾다가 포기 ([Errno 22] invalid mode or filename)

 

python sample_generator.py

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

내 계정에 라이브러리 생성

 

 

복사할 곳의 code를 클릭, https 의 링크 복사

 

 

 

내 로컬 컴퓨터에서 git bash 실행, 아래 명령어 입력

git clone https://github.com/needleworm/bhban_rpa.git

 

 

 

git bash 클론 fatal: working tree '...' already exists. 오류 발생 시 해결

unset GIT_DIR

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

누르면 이동

 

 

근데 int랑 일부 문법 안써져서 우가우가 함
11 단원 무지개 부분 예시는 봐지지도 않음 ㅠ
가제는 그냥 내가 기분내려고 붙인거

사용도구 : 인터넷, 나, 노트북, (가끔)구글번역기

레퍼런스 누름 나오는 거. 함수이름 0.5초면 까먹어서 캡쳐함..ㅋㅋ 

 

 

 

이 전엔 막히는거 없어서 그냥 쭉쭉 풀고 차마 기록하고 찍을 생각은 안함

 

 

Unit 8 / Lesson 5

(가제) 세계여행

아이큐문제인가 머리굴렸는데 핵심은 그게 아니라고 판단하고.. 빠르게 goal 달성함.
핵심은 중복을 피해서 길찾아가는 게 아니라 '마무리 자세'(어딜보는지)임.. 조건활용이랑..ㅋㅋ 

* 주의점 - 도중에 바라보는 방향을 판단하면 virtual direction은 알 수 없다고 뜸
그냥 의식의 흐름대로 짜고 일부 문법들 안써져서 졸라리 지저분함

 

function main() {  
      putBeeperLine(); 
      turnLeft();
      move();
      turnLeft();
      
      putBeeperLine(); 
      turnRight();
      
      if(frontIsBlocked()){ 
          meetEndLine();
      } else{  
         move();
         turnRight();
      }
      
      putBeeperLine(); 
      turnLeft();
      move();
      turnLeft();
      
      putBeeperLine(); 
      turnRight();
      if(frontIsBlocked()){ 
          meetEndLine();
      } else{  
         move();
         turnRight();
      }
      
      putBeeperLine(); 
      turnLeft();
      
      if(frontIsBlocked()){
         turnRight();
      }
      
      if(frontIsClear()){ 
      move();
      turnLeft();
      
      putBeeperLine(); 
      turnRight();
      if(frontIsBlocked()){ 
          meetEndLine();
      } else{  
         move();
         turnRight();
      }
      
      putBeeperLine(); 
      turnLeft();
      move();
      turnLeft(); 
      
      putBeeperLine();  
      turnRight();
      if(frontIsBlocked()){ 
          meetEndLine();
      } else{  
         move();
         turnRight();
      } 
      }
      
}

function meetEndLine(){
   turnRight(); 
   move();
   move();
   move();
   move();
   move();
   move();
   move(); 
}

function turnRight()
{
   turnLeft();
   turnLeft();
   turnLeft();
}

function putBeeperLine()
{
   putBeeper();
   
   while(frontIsClear()) {
      move();
      putBeeper();  
   }  
}

 

 

Unit 9 / Lesson 2

(가제) 세로줄 쌓기

 

//Karel must help rebuild 
//broken columns. Make a 
//column of beepers above
//each beeper you find on
//the first row
function main() {
   while(frontIsClear()){
      move();
      
      // make beeper column
      if(beepersPresent()){
         turnLeft();
         putBeeperLine(); 
         turnRight();
         turnRight(); 
          
         while(frontIsClear()){
            move();
         }
         turnLeft();
      }
      
   }
}

function turnRight(){
   turnLeft();
   turnLeft();
   turnLeft();
}

function putBeeperLine()
{ 
   while(frontIsClear()) {
      move();
      putBeeper();  
   }  
}

 

 

Unit 12 / Lesson 1 (마지막 문제)

(가제) 중간 지점 찾기

 

//Your final task is to teach
//Karel to find the midpoint
//of any world. You can assume
//that all worlds are square.
function main(){ 
   // count
   int i = 0;
   while(frontIsClear()) {
      move();  
      //i++; //not working
      i = i + 1;
   }  
   i = i/2 + 1; //beeper position
   // direction chg
   turnLeft();
   turnLeft();
   for(int j=0; j<i-1; j++){
       move();
   }   
   // put beeper
   putBeeper();
   // direction chg
   turnright();
   turnright();
   // run to the goal
   while(frontIsClear()) {
      move(); 
   }
}

https://stanford.edu/~cpiech/karel/lessons.html#/english/unit12/lesson1

&amp;amp;nbsp;

 

변수 선언이 함수 내에서밖에 안되서 다르게 푸는 중
지금은 5*5짜리 안됨..이게 코든가 노가단가 단순화시켜야지 이건아닌듯

function main() {
   touchAngle(); //beepers with restart
    
   chgAngle(); //4
   chgAngle();
   chgAngle();
   chgAngle();
     
   move();
   putBeeper();
   move();
   turnAround(); 
   
   move();
   putBeeper();  
   move(); 
   turnAround();
   
   while(frontIsClear()) {
      move();
   } 
   
   delBeeper();  
   
   while(frontIsClear()) {
      move();
   }
} 

function chgAngle(){
   move(); 
   while(noBeepersPresent()) {
      move();
   }
   turnAround(); 
   move();
   putBeeper();
}

function delBeeper(){
   turnAround();
   while(frontIsClear()) {
      pickBeeper();
      move();
   }
   pickBeeper();
   turnAround();
}

function touchAngle(){ 
   while(frontIsClear()) {
      move();
	}
   putBeeper();
   turnAround();
   while(frontIsClear()) {
      move();
	}
   turnAround(); 
   putBeeper();
}

 

그냥 기록용..

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

일반적으로 솔루션 파일을 만들어 작업하지 않고 코드 파일들만 갖고와서 새로운 프로젝트 만들기로 솔루션 파일을 만들다가 맞닥뜨린 오류이다. 

 

비주얼스튜디오 함수에서 참조되는 확인할 수 없는 외부 기호 오류는 링커 에러로

1) main 함수가 정의되지 않았거나
2) 미리 정의되지 않은 변수나 함수가 사용되었거나
3) x86, x64가 혼합되었거나 잘못 선택되어 솔루션이 빌드되었을 때 등등

발생하는데 다른 글쓴이 말처럼 내 경우도 마지막 경우였다. 바꿔주니 문제 없이 실행된다.
(바꿔주고 재빌드 해야함)

 

 

 

* 오류목록말고 출력 탭을 보면 "구성 : Debug Win32" 등으로 출력된다.

 

참고한 곳 : https://davi06000.tistory.com/5

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

 

파일을 분할해본다. 각각의 클래스마다 선언은 .h파일에, 정의는 .cpp 파일에 저장한다.
프로그램 관리가 편해지고, 클래스의 구성이 한 눈에 들어와서 프로그램 내용 파악이 수월해진다.
6단계에서도 나눴었으나 좀 더 체계적으로 나누었다.

 

 

과거 진행한 OOP 단계별 프로젝트

[윤성우 열혈 c++] OOP 단계별 프로젝트 01단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 02단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 03단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 04단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 05단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 06단계

 

 

프로그램 설명

다음의 구조로 파일 분할을 해 보자.

Account.h, Account.cpp  
NormalAccount.h, NormalAccount.cpp 
HighCreditAccount.h, HighCreditAccount.cpp
AccountHandler.h, AccountHandler.cpp 
BankingCommonDecl.h ---- 공통헤더 및 상수 선언들
BankingSystemMain.cpp ---- main 함수의 정의

 

 

 

 

 

 

 

Account.h
#pragma once
/**
*	파일이름 : Account.h
*	작성자 : 코딩맛집
*	업데이트 정보 : 2021-11-18 파일버전 0.7
*	계좌
*/

#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__

class Account {
private:
    int accID; //계좌 ID
    int balance; // 잔액
    char* cusName; //고객이름 
public:
    Account(int _accID, int _balance, char* _name); //생성자
    Account(const Account& ref); //복사생성자

    int GetAccID() const;    // 계좌 ID 반환 
    virtual void Deposit(int money); // 입금     //virtual 추가
    int WithDraw(int money);  // 출금
    void ShowAccInfo() const;  // 개인계좌조회   

    ~Account(); // 소멸자
};

#endif

 

 

Account.cpp
/**
*	파일이름 : Account.cpp
*	작성자 : 코딩맛집
*	업데이트 정보 : 2021-11-18 파일버전 0.7
*	계좌
*/

#include "BankingCommonDecl.h"
#include "Account.h"

// Account 생성자 
Account::Account(int _accID, int _balance, char* _name)  // 계좌개설 - ID, 고객이름, 돈
    : accID(_accID), balance(_balance)
{
    cusName = new char[strlen(_name) + 1]; //고객이름 객체 포인터로 동적할당
    strcpy(cusName, _name);
}

// 실제 호출되지는 않는 Account복사생성자
// 깊은 복사를 원칙으로 정의
Account::Account(const Account& ref)
    : accID(ref.accID), balance(ref.balance)
{
    cusName = new char[strlen(ref.cusName) + 1]; //고객이름 객체 포인터로 동적할당
    strcpy(cusName, ref.cusName);
}

// Account 소멸자
Account::~Account() // 소멸자
{
    delete[] cusName;
}

// 계좌 ID 반환
int Account::GetAccID() const  // 내부 출력문이나 값의 변동이 없는 경우 const
{
    return accID;
}

// 개인 계좌조회
void Account::ShowAccInfo() const
{
    // 내부 출력문이나 값의 변동이 없는 경우 const
    cout << "계좌ID: " << accID << endl;
    cout << "이름: " << cusName << endl;
    cout << "잔액: " << balance << endl << endl;
}

// 입출금
void Account::Deposit(int money)
{
    balance += money;
}
int Account::WithDraw(int money)
{
    if (balance < money) //잔액<출금액 
    {
        return 0;
    }
    balance -= money;
    return money;
}

 

 

NormalAccount.h, NormalAccount.cpp
#pragma once
/**
*	파일이름 : NormalAccount.h
*	작성자 : 코딩맛집
*	업데이트 정보 : 2021-11-18 파일버전 0.7
*	요약 : 보통예금계좌
*	객체를 생성할 때 계좌 기본이율을 등록할 수 있다
*	계좌개설 과정 초기 입금액은 이자가 붙지 않는다.
*	이자계산액의 소수점 이하 금액은 무시한다. (버림)
*/

#ifndef __NORMAL_ACCOUNT_H__
#define __NORMAL_ACCOUNT_H__

#include "Account.h"

class NormalAccount: public Account //Account 상속
{
public:
	NormalAccount(int _accID, int _balance, char* _name, int _basicInterestRate);
	~NormalAccount();
private:
	int basicInterestRate; // 기본이율 (%단위)

public:
	//추가된 입금 + 이자율 계산식......뒤집어쓰니까 virtual
	virtual void Deposit(int money);
}; 

#endif
#include "NormalAccount.h"

NormalAccount::NormalAccount(int _accID, int _balance, char* _name, int _basicInterestRate)
	: Account(_accID, _balance, _name), basicInterestRate(_basicInterestRate)
{ }

NormalAccount::~NormalAccount()	
{ }

void NormalAccount::Deposit(int money)
{
	Account::Deposit(money); //원금추가
	Account::Deposit(money*(basicInterestRate/100.0)); //이자추가
}

 

 

HighCreditAccount.h
#pragma once
/**
*	파일이름 : HighCreditAccount.h
*	작성자 : 코딩맛집
*	업데이트 정보 : 2021-11-18 파일버전 0.7
*	요약 : 신용신뢰계좌
*	객체를 생성할 때 계좌 기본이율을 등록할 수 있다
*	계좌개설 과정 초기 입금액은 이자가 붙지 않는다.
*	이자계산액의 소수점 이하 금액은 무시한다. (버림)
*	신용등급 정보 A(7%), B(4%), C(2%) 셋 중 하나를 계좌개설 시 등록한다.
*	등급별 기본이율에 각각의 이율을 추가 제공한다.
*/ 

#ifndef __HIGHCREDIT_ACCOUNT_H__
#define __HIGHCREDIT_ACCOUNT_H__

#include "NormalAccount.h"

class HighCreditAccount : public NormalAccount
{
public:
	HighCreditAccount(int _id, int _balance, char* _name, int _interRate, int _creditLevel);
	~HighCreditAccount();
private: 
	int creditLevel; //신용등급
public:
	virtual void Deposit(int money);
};
#endif
#include "HighCreditAccount.h"

HighCreditAccount::HighCreditAccount(int _id, int _balance, char* _name, int _interRate, int _creditLevel)
	: NormalAccount(_id, _balance, _name, _interRate), creditLevel(_creditLevel)
{	}

HighCreditAccount::~HighCreditAccount()
{	}

void HighCreditAccount::Deposit(int money)
{
	NormalAccount::Deposit(money); //원금과 이자추가 
	Account::Deposit(money*(creditLevel/100.0)); // 특별이자 추가
}

 

 

AccountHandler.h
#pragma once
/**
*	파일이름 : AccountHandler.h
*	작성자 : 코딩맛집
*	업데이트 정보 : 2021-11-18 파일버전 0.7
*	컨트롤 클래스
*/

#ifndef __ACCOUNT_HANDLER_H__
#define __ACCOUNT_HANDLER_H__

#include "Account.h"

class AccountHandler {
private:    
    Account* accArr[100]; //Account 저장을 위한 배열
    int accNum; //저장된 Account 수    
public:
    AccountHandler();  //생성자
    
    void ShowMenu(void) const; //메뉴출력
    void MakeAccount(void); //계좌개설
    void DepositMoney(void); //입금
    void WithdrawMoney(void); //출금
    void ShowAllAccInfo(void) const; //잔액조회

    void MakeNormalAccount(); // 보통예금계좌 개설
    void MakeHighCreditAccount(); // 신용신뢰계좌 개설

    ~AccountHandler(); //소멸자
};

#endif // !__ACCOUNT_HANDLER_H__

 

 

AccountHandler.cpp
/**
*	파일이름 : AccountHandler.h
*	작성자 : 코딩맛집
*	업데이트 정보 : 2021-11-18 파일버전 0.7
*	컨트롤 클래스
*/

#include "BankingCommonDecl.h"
#include "Account.h"
#include "AccountHandler.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"

//메뉴출력
void AccountHandler::ShowMenu(void) const {
    cout << "-----Menu-----" << endl;
    cout << "1. 계좌개설" << endl;
    cout << "2. 입금" << endl;
    cout << "3. 출금" << endl;
    cout << "4. 계좌번호 전체 출력" << endl;
    cout << "5. 프로그램 종료" << endl;
}

// AccountHandler 생성자
AccountHandler::AccountHandler()
    : accNum(0)
{}

// AccountHandler 소멸자
AccountHandler::~AccountHandler()
{
    for (int i = 0; i < accNum; i++)
    {
        delete accArr[i];
    }
}

//계좌개설
void AccountHandler::MakeAccount(void)
{ 
    int accountType;   

    cout << "[계좌종류선택]" << endl;
    cout << "1. 보통예금계좌 2. 신용신뢰계좌" << endl;
    cout << "선택(숫자입력) : "; cin >> accountType;

    if (accountType == NORMAL) //보통예금계좌
    {      
        MakeNormalAccount();
    }
    else // 신용신뢰계좌
    {
        MakeHighCreditAccount();
    }       
}


// 보통예금계좌 개설
void AccountHandler::MakeNormalAccount()
{
    int id;
    char name[NAME_LEN];
    int balance; 
    int interRate;

    cout << "[보통예금계좌 개설]" << endl;
    cout << "계좌ID: (숫자로 입력) "; cin >> id;
    cout << "이름: "; cin >> name;
    cout << "입금액: "; cin >> balance;
    cout << "이자율: "; cin >> interRate;
    cout << endl;

    accArr[accNum++] = new NormalAccount(id, balance, name, interRate);
}


// 신용신뢰계좌 개설
void AccountHandler::MakeHighCreditAccount()
{
    int id;
    char name[NAME_LEN];
    int balance; 
    int interRate;
    int creditLevel;

    cout << "[신용신뢰계좌 개설]" << endl;
    cout << "계좌ID: (숫자로 입력) "; cin >> id;
    cout << "이름: "; cin >> name;
    cout << "입금액: "; cin >> balance;
    cout << "이자율: "; cin >> interRate;
    cout << "신용등급(1toA, 2toB, 3toC이며 1, 2, 3 중 입력): "; cin >> creditLevel;
    cout << endl;    
    
    // 신용등급 처리   
    switch (creditLevel)
    {
    case 1: 
        // 1을 입력했을 때
        accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, A); //7%
        break;
    case 2:
        accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, B); //4%
        break;
    case 3:
        accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, C); //2%
        break;
    }    
}
 

//입금
void AccountHandler::DepositMoney(void) {
    int money;
    int id;
    cout << "[입  금]" << endl;
    cout << "계좌ID: "; cin >> id;
    cout << "입금액: "; cin >> money;


    for (int i = 0; i < accNum; i++)
    {
        if (accArr[i]->GetAccID() == id)
        {
            accArr[i]->Deposit(money);
            cout << "입금완료" << endl << endl;
            return;
        }
    }
    cout << "유효하지 않은 ID 입니다." << endl << endl;
}

//출금
void AccountHandler::WithdrawMoney(void) {
    int money;
    int id;
    cout << "[출  금]" << endl;
    cout << "계좌ID: "; cin >> id;
    cout << "출금액: "; cin >> money;

    for (int i = 0; i < accNum; i++)
    {
        if (accArr[i]->GetAccID() == id)
        {
            if (accArr[i]->WithDraw(money) == 0) //잔액보다 출금액이 크면
            {
                cout << "잔액부족" << endl << endl;
                return;
            }
            cout << "출금완료" << endl << endl;
            return;
        }
    }
    cout << "유효하지 않은 ID 입니다" << endl << endl;
}

// 전체고객 잔액조회
void AccountHandler::ShowAllAccInfo(void) const
{
    for (int i = 0; i < accNum; i++)
    {
        accArr[i]->ShowAccInfo();
    }
}

 

 

BankingCommonDecl.h 
#pragma once
/**
*	파일이름 : BankingCommonDecl.h 
*	작성자 : 코딩맛집
*	업데이트 정보 : 2021-11-18 파일버전 0.7
*	공통헤더 및 상수 선언
*/

#ifndef __BANKING_COMMON_H__
#define __BANKING_COMMON_H__

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>

using namespace std;
const int NAME_LEN = 20;

//  프로그램 사용자의 선택 메뉴
enum { MAKE = 1, DEPOSIT, WITHDRAW, INQUIRE, EXIT };

// 계좌종류
enum AccountType { NORMAL = 1, HIGHCREDIT };

// 신용등급
enum CreditRating { A = 7, B = 4, C = 2 };

#endif; // !__BANKING_COMMON_H__

 

 

BankingSystemMain.cpp
/**
*   소프트웨어 버전 : BankingSystemMain Ver 0.7
*   소프트웨어 요약 : 은행 계좌 관리 프로그램
* 
*	파일이름 : BankingSystemMain.cpp
*	작성자 : 코딩맛집
*	업데이트 정보 : 2021-11-18 파일버전 0.7
*	파일요약 : 메인함수 있는 부분
*/

#include "BankingCommonDecl.h"
#include "AccountHandler.h"


int main()
{
    AccountHandler hdr;
    int choice;

    while (1)
    {
        hdr.ShowMenu(); //메뉴선택모드

        cout << "선택(1~5까지의 숫자만 입력) : ";
        cin >> choice;
        cout << endl;

        switch (choice)
        {
        case MAKE:
            hdr.MakeAccount();
            break;
        case DEPOSIT:
            hdr.DepositMoney();
            break;
        case WITHDRAW:
            hdr.WithdrawMoney();
            break;
        case INQUIRE:
            hdr.ShowAllAccInfo();
            break;
        case EXIT:
            return 0;
        default:
            cout << "잘못된 선택" << endl;
        }
    }
    return 0;
}

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
구문 오류 : ';'이(가) '*' 앞에 없습니다.

 

이 오류는 상호참조가 아닌지 의심해 보아야 한다.

Pointer만 필요하고 인스턴스 생성을 하지 않을진데 .h 헤더 파일을 include 하고 있는지 확인하라는 말이다.
만일 그러하다면, 헤더파일을 없애고 Pointing할 클래스만 위에 선언을 해주라.
A.h에서 B.h를 include 해서 B의 객체를 사용하고 있는 경우에, A의 포인터를 B에 전해주기 위해서는 B.h에서 A클래스를 선언하고 (B.h에서 A.h를 include하면 상호참조 오류가 발생) B.cpp에서 A.h를 include하여 사용하면 된다. 


출처: https://take-a-step-first.tistory.com/298 [한 걸음 앞으로. ]

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

상속의 목적은 명확해야 하고 그렇지 않다면 안하는 편이 좋다.
상속이 필요한 대표적이며 중요한 이유, 이점을 정리해본다.

공통적인 기능을 묶어 추가 삭제 등 변경사항이 생겨도 자식 클래스에 일일히 적용하지 않아도 된다 -> 확장성이 좋다
다른 곳에도 구현해 둔 클래스를 붙였다 뗐다 할 수 있다 -> 재사용이 가능

● 장점 : 유지보수가 쉬워지고, 확장성이 좋아지며, 모듈화를 통해 재사용이 가능하며, 코드가 간결해져 개발시간을 단축시킬 수 있다.

 

 

과거 진행한 OOP 단계별 프로젝트

[윤성우 열혈 c++] OOP 단계별 프로젝트 01단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 02단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 03단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 04단계

[윤성우 열혈 c++] OOP 단계별 프로젝트 05단계

 

 

프로그램 설명

기존 Account 클래스에는 이자와 관련한 부분이 없으니 6단계에서는 Account 클래스를 상속하는 2개의 클래스를 추가 정의한다.

1) NormalAccount  :  보통예금계좌 (최소한의 이자를 지급하는 자유입출금계좌)
2) HighCreditAccount  :  신용신뢰계좌 (신용도가 높은 일부 고객만 개설되는 높은 이율 계좌)

NormalAccount  클래스는 객체의 생성 과정에서(생성자를 통해) 이율정보를 등록할 수 있게 정의한다.
HighCreditAccount 클래스에는 다음 특성을 부여해 정의하자.

1) NormalAccount 클래스처럼 객체 생성과정에서 기본이율을 등록할 수 있다
2) 고객의 신용등급을 A, B, C로 나누고 계좌개설 시 신용등급 정보를 등록한다.
3) A, B, C 등급별로 각각 기본이율에 7%, 4%, 2%의 이율을 추가 제공한다.

편의상 이자는 입금 시 이자가 원금에 더해지는 것으로 계산한다.
모든 계좌에는 다음 조건을 적용한다.

1) 계좌개설 과정에서 초기 입금되는 금액에 대해서는 이자를 계산하지 않는다.
2) 계좌개설 후 별도의 입금과정을 거칠 때에만 이자가 발생하는 것으로 간주한다.
3) 이자의 계산과정에서 발생하는 소수점 이하의 금액은 무시한다.

컨트롤 클래스인 AccountHandler 클래스에는 큰 변화가 없어야 한다.
(계좌의 종류가 늘어난 만큼 메뉴의 선택과 데이터의 입력과정에서의 불가피한 변경은 허용)

 

 

실행의 예

계좌의 개설과정 1

-----Menu-----
1. 계좌개설
2. 입금
3. 출금
4. 계좌번호 전체 출력
5. 프로그램 종료
선택: 1


[계좌종류선택]
1. 보통예금계좌 2. 신용신뢰계좌
선택 : 1

[보통예금계좌 개설]
계좌ID: 123
이름: 이종석
입금액: 0
이자율: 3

 

 

계좌의 개설과정 2

-----Menu-----
1. 계좌개설
2. 입금
3. 출금
4. 계좌번호 전체 출력
5. 프로그램 종료
선택: 1


[계좌종류선택]
1. 보통예금계좌 2. 신용신뢰계좌
선택 : 2

[신용신뢰계좌 개설]
계좌ID: 7272
이름: 이수혁
입금액: 10000
이자율: 9
신용등급(1toA, 2toB, 3toC): 2

 

 

 

 

 

 

구현코드는 나름대로 나눠서 정리해 봤다.

 

BankingSystemMain.cpp
// BankingSystemVer06.cpp - 은행 계좌 관리 프로그램 6
#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <cstring> 

#include "Account.h"
#include "AccountHandler.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"

using namespace std;

//1. 계좌개설
//2. 입금
//3. 출금
//4. 계좌번호 전체 출력
//5. 프로그램 종료
enum { MAKE = 1, DEPOSIT, WITHDRAW, INQUIRE, EXIT };

/********** 메인 클래스 AccountHandler **********/
int main()
{
    AccountHandler hdr;
    int choice;

    while (1)
    {
        hdr.ShowMenu(); //메뉴선택모드

        cout << "선택(1~5까지의 숫자만 입력) : ";
        cin >> choice;
        cout << endl;

        switch (choice)
        {
        case MAKE:
            hdr.MakeAccount();
            break;
        case DEPOSIT:
            hdr.DepositMoney();
            break;
        case WITHDRAW:
            hdr.WithdrawMoney();
            break;
        case INQUIRE:
            hdr.ShowAllAccInfo();
            break;
        case EXIT:
            return 0;
        default:
            cout << "잘못된 선택" << endl;
        }
    }
    return 0;
}

 

 

 

Account.h, Account.cpp
#pragma once
class Account {
private:
    int accID; //계좌 ID
    int balance; // 잔액
    char* cusName; //고객이름 
public:
    Account(int _accID, int _balance, char* _name); //생성자
    Account(const Account& ref); //복사생성자

    int GetAccID() const;    // 계좌 ID 반환 
    virtual void Deposit(int money); // 입금     //virtual 추가
    int WithDraw(int money);  // 출금
    void ShowAccInfo() const;  // 개인계좌조회   

    ~Account(); // 소멸자
};
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "Account.h"
using namespace std;

// Account 생성자 
Account::Account(int _accID, int _balance, char* _name)  // 계좌개설 - ID, 고객이름, 돈
    : accID(_accID), balance(_balance)
{
    cusName = new char[strlen(_name) + 1]; //고객이름 객체 포인터로 동적할당
    strcpy(cusName, _name);
}

// 실제 호출되지는 않는 Account복사생성자
// 깊은 복사를 원칙으로 정의
Account::Account(const Account& ref)
    : accID(ref.accID), balance(ref.balance)
{
    cusName = new char[strlen(ref.cusName) + 1]; //고객이름 객체 포인터로 동적할당
    strcpy(cusName, ref.cusName);
}

// Account 소멸자
Account::~Account() // 소멸자
{
    delete[] cusName;
}

// 계좌 ID 반환
int Account::GetAccID() const  // 내부 출력문이나 값의 변동이 없는 경우 const
{
    return accID;
}

// 개인 계좌조회
void Account::ShowAccInfo() const
{
    // 내부 출력문이나 값의 변동이 없는 경우 const
    cout << "계좌ID: " << accID << endl;
    cout << "이름: " << cusName << endl;
    cout << "잔액: " << balance << endl << endl;
}

// 입출금
void Account::Deposit(int money)
{
    balance += money;
}
int Account::WithDraw(int money)
{
    if (balance < money) //잔액<출금액 
    {
        return 0;
    }
    balance -= money;
    return money;
}

 

 

 

AccountHandler.h, AccountHandler.cpp
#pragma once
/********** 컨트롤 클래스 AccountHandler **********/
class AccountHandler {
private:
    // 전역 변수였던 것들
    Account* accArr[100]; //Account 저장을 위한 배열
    int accNum; //저장된 Account 수    
public:
    AccountHandler();  //생성자

    // 전역함수였던 것들
    void ShowMenu(void) const; //메뉴출력
    void MakeAccount(void); //계좌개설
    void DepositMoney(void); //입금
    void WithdrawMoney(void); //출금
    void ShowAllAccInfo(void) const; //잔액조회

    void MakeNormalAccount(); // 보통예금계좌 개설
    void MakeHighCreditAccount(); // 신용신뢰계좌 개설

    ~AccountHandler(); //소멸자
};
#include <iostream>
#include "Account.h"
#include "AccountHandler.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"

using namespace std;

const int NAME_LEN = 20; //이름의길이

//메뉴출력
void AccountHandler::ShowMenu(void) const {
    cout << "-----Menu-----" << endl;
    cout << "1. 계좌개설" << endl;
    cout << "2. 입금" << endl;
    cout << "3. 출금" << endl;
    cout << "4. 계좌번호 전체 출력" << endl;
    cout << "5. 프로그램 종료" << endl;
}

// AccountHandler 생성자
AccountHandler::AccountHandler()
    : accNum(0)
{}

// AccountHandler 소멸자
AccountHandler::~AccountHandler()
{
    for (int i = 0; i < accNum; i++)
    {
        delete accArr[i];
    }
}

// 계좌종류
enum AccountType { NORMAL = 1, HIGHCREDIT };

// 신용등급
enum CreditRating { A = 7, B = 4, C = 2 };


//계좌개설
void AccountHandler::MakeAccount(void)
{
   /* int id;
    char name[NAME_LEN];
    int balance;*/
    int accountType; 

   /* cout << "[계좌개설]" << endl;
    cout << "계좌ID:(숫자로 입력) "; cin >> id;
    cout << "이름: "; cin >> name;
    cout << "입금액: "; cin >> balance;
    cout << endl;
    accArr[accNum++] = new Account(id, balance, name);*/

    cout << "[계좌종류선택]" << endl;
    cout << "1. 보통예금계좌 2. 신용신뢰계좌" << endl;
    cout << "선택(숫자입력) : "; cin >> accountType;

    if (accountType == NORMAL) //보통예금계좌
    {      
        MakeNormalAccount();
    }
    else // 신용신뢰계좌
    {
        MakeHighCreditAccount();
    }       
}


// 보통예금계좌 개설
void AccountHandler::MakeNormalAccount()
{
    int id;
    char name[NAME_LEN];
    int balance; 
    int interRate;

    cout << "[보통예금계좌 개설]" << endl;
    cout << "계좌ID: (숫자로 입력) "; cin >> id;
    cout << "이름: "; cin >> name;
    cout << "입금액: "; cin >> balance;
    cout << "이자율: "; cin >> interRate;
    cout << endl;

    accArr[accNum++] = new NormalAccount(id, balance, name, interRate);
}


// 신용신뢰계좌 개설
void AccountHandler::MakeHighCreditAccount()
{
    int id;
    char name[NAME_LEN];
    int balance; 
    int interRate;
    int creditLevel;

    cout << "[신용신뢰계좌 개설]" << endl;
    cout << "계좌ID: (숫자로 입력) "; cin >> id;
    cout << "이름: "; cin >> name;
    cout << "입금액: "; cin >> balance;
    cout << "이자율: "; cin >> interRate;
    cout << "신용등급(1toA, 2toB, 3toC이며 1, 2, 3 중 입력): "; cin >> creditLevel;
    cout << endl;    
    
    // 신용등급 처리   
    switch (creditLevel)
    {
    case 1: 
        // 1을 입력했을 때
        accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, A); //7%
        break;
    case 2:
        accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, B); //4%
        break;
    case 3:
        accArr[accNum++] = new HighCreditAccount(id, balance, name, interRate, C); //2%
        break;
    }    
}




//입금
void AccountHandler::DepositMoney(void) {
    int money;
    int id;
    cout << "[입  금]" << endl;
    cout << "계좌ID: "; cin >> id;
    cout << "입금액: "; cin >> money;


    for (int i = 0; i < accNum; i++)
    {
        if (accArr[i]->GetAccID() == id)
        {
            accArr[i]->Deposit(money);
            cout << "입금완료" << endl << endl;
            return;
        }
    }
    cout << "유효하지 않은 ID 입니다." << endl << endl;
}

//출금
void AccountHandler::WithdrawMoney(void) {
    int money;
    int id;
    cout << "[출  금]" << endl;
    cout << "계좌ID: "; cin >> id;
    cout << "출금액: "; cin >> money;

    for (int i = 0; i < accNum; i++)
    {
        if (accArr[i]->GetAccID() == id)
        {
            if (accArr[i]->WithDraw(money) == 0) //잔액보다 출금액이 크면
            {
                cout << "잔액부족" << endl << endl;
                return;
            }
            cout << "출금완료" << endl << endl;
            return;
        }
    }
    cout << "유효하지 않은 ID 입니다" << endl << endl;
}

// 전체고객 잔액조회
void AccountHandler::ShowAllAccInfo(void) const
{
    for (int i = 0; i < accNum; i++)
    {
        accArr[i]->ShowAccInfo();
    }
}

 

 

 

NormalAccount.h, NormalAccount.cpp
#pragma once
/**
*	객체를 생성할 때 계좌 기본이율을 등록할 수 있다
*	계좌개설 과정 초기 입금액은 이자가 붙지 않는다.
*	이자계산액의 소수점 이하 금액은 무시한다. (버림)
*/
class NormalAccount: public Account //Account 상속
{
public:
	NormalAccount(int _accID, int _balance, char* _name, int _basicInterestRate);
	~NormalAccount();
private:
	int basicInterestRate; // 기본이율 (%단위)

public:
	//추가된 입금 + 이자율 계산식......뒤집어쓰니까 virtual
	virtual void Deposit(int money);
};
#include <iostream>
#include "Account.h"
#include "NormalAccount.h"

NormalAccount::NormalAccount(int _accID, int _balance, char* _name, int _basicInterestRate)
	: Account(_accID, _balance, _name), basicInterestRate(_basicInterestRate)
{ }

NormalAccount::~NormalAccount()	
{ }

void NormalAccount::Deposit(int money)
{
	Account::Deposit(money); //원금추가
	Account::Deposit(money*(basicInterestRate/100.0)); //이자추가
}

 

 

 

HighCreditAccounth, HighCreditAccount.cpp
#pragma once
/**
*	객체를 생성할 때 계좌 기본이율을 등록할 수 있다
*	계좌개설 과정 초기 입금액은 이자가 붙지 않는다.
*	이자계산액의 소수점 이하 금액은 무시한다. (버림)
*	신용등급 정보 A(7%), B(4%), C(2%) 셋 중 하나를 계좌개설 시 등록한다.
*	등급별 기본이율에 각각의 이율을 추가 제공한다.
*/
class HighCreditAccount : public NormalAccount
{
public:
	HighCreditAccount(int _id, int _balance, char* _name, int _interRate, int _creditLevel);
	~HighCreditAccount();
private: 
	int creditLevel; //신용등급
public:
	virtual void Deposit(int money);
};
#include <iostream>
#include "Account.h"
#include "NormalAccount.h"
#include "HighCreditAccount.h"

HighCreditAccount::HighCreditAccount(int _id, int _balance, char* _name, int _interRate, int _creditLevel)
	: NormalAccount(_id, _balance, _name, _interRate), creditLevel(_creditLevel)
{	}

HighCreditAccount::~HighCreditAccount()
{	}

void HighCreditAccount::Deposit(int money)
{
	NormalAccount::Deposit(money); //원금과 이자추가 
	Account::Deposit(money*(creditLevel/100.0)); // 특별이자 추가
}

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90

C++에서 미리 함수를 정의하지 않으면 순차적으로 코드를 읽어들여 오류를 발생시킨다. (식별자 찾을 수 없음)
그러나 전방선언이 이뤄졌다면 컴파일러는 오류 없이 지나간다.

 

 

C++ 전방선언 (Forward Declaration)

식별자를 정의하기 전 식별자의 존재를 컴파일러에 미리 알리는 것
필요에 따라 함수, 변수, 클래스 등을 전방선언한다.

컴파일 시간을 단축시킨다. 
헤더포함 의존성을 줄여준다.

int x; //선언
x = 42; //x를 사용

 

 

 

C++ 클래스 전방선언

헤더파일에서 헤더파일을 포함시키는 행위는 컴파일 시간을 증가시킨다. (하나의 헤더파일이 변경되어도 include한 파일들이 모두 재컴파일)

// #include "ObjectA.h" 생략하고
class ObjectA; //클래스 전방선언


그래서 포인터 객체를 선언할 때 클래스 선언 전에 필요한 클래스를 명시해 헤더파일의 중복을 막아주는 것이다.

- C++ 클래스 전방선언은 헤더포함 의존성을 최소화
- 해당 헤더의 불필요한 정보 비노출

 

ObjectA *objA;
// ObjectA objA; //불가능

이렇게 사용하는데 헤더파일을 포함하지 않으니 클래스에 대한 정보가 없어서 
포인터 객체만 사용 가능하다.

단, 전방 선언을 사용할 경우, 전방선언한 클래스에 대한 객체는 포인터형으로 선언해야 한다.

(

해당 객체 할당 크기를 정확히 파악할 수 없어서이며 포인터형으로 선언 시 4바이트(32bit OS에서)를 할당)

Mother* m_pMainFamily = nullptr;

 

 

C++ 함수 전방선언

함수의 몸체를 정의하기 전 함수의 존재를 컴파일러에 미리 알리는 것을 말한다. 
함수 전방선언 방법은 함수 원형 (함수 선언문)을 사용하여 작성하면 된다.
그러면 리턴타입, 이름, 매개변수는 들어가지만 함수 몸체는 포함하지 않고 명령문이므로 세미콜론으로 끝난다.

#include <iostream>

int add(int x, int y); //전방선언

int main()
{
	...
	add(3, 4);
    return 0;
}

int add(int x, int y) //정의
{
	return x+y;
}

사용은 이런 식으로 한다. 함수 원형에서 매개변수의 이름을 생략해서 선언할 수도 있다.

int add(int, int); // 전방선언 이렇게도 가능

 

 

C++ 선언과 정의의 차이점

- 선언 (declaration) : 식별자(변수/함수이름) 및 해당타입의 존재를 컴파일러에 알려준다. 
선언하지 않고 식별자를 사용하면 컴파일러에서 에러가 발생한다.

- 정의 (definition) : 식별자를 실제로 구현하거나 인스턴스화(메모리 할당) 한다.
정의하지 않고 식별자를 사용하면 링커에서 에러가 발생한다.

- C++에서 모든 정의는 선언으로도 간주한다. (int x;)
대부분은 정의만 필요하나 정의되기 전에 식별자를 사용해야 한다면 명시적인 선언이 필요하다.

 

 

C++ 매개변수 / 리턴 타입을 위한 이름만 참조하는 전방선언

함수의 매개변수나 리턴 타입으로 이름만 사용될 경우 포인터형이 아닌 객체를 사용할 수 있다.
함수 body 와 그 함수를 호출할 경우에만 클래스의 크기가 필요하기 때문이다.

// 전방선언
class Archer;

class RangeAttack
{
public:
    void SetArcher(Archer archer);
    Archer GetArcher() const;

 

 

 

 

 

 

참고한 곳 

- https://boycoding.tistory.com/143

- https://eastroot1590.tistory.com/entry/C-Reference-%ED%81%B4%EB%9E%98%EC%8A%A4-%EC%A0%84%EB%B0%A9%EC%84%A0%EC%96%B8class-forward-declaration

- 3

- http://egloos.zum.com/sweeper/v/2827565

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,
728x90
728x90
복사생성자 호출 시점을 아는 것은 중요하며, 총 3가지가 있습니다.

1. 기존에 생성된 객체를 이용해서 새로운 객체를 초기화 (복사 등)

2. Call by value 방식의 함수 호출 과정에서 객체를 인자로 전달할 때

3. 객체를 반환할 때 참조형으로 반환하지 않는 경우. (임시객체 생성)

 

* 임시객체  : 힙 이외의 공간에 생성되는 것

A함수에 int형 a인자가 들어오고 a를 return 한다고 할 때
A함수에서만 통용되고 없어지는 임시객체를 생성

 

 

복사생성자 호출 시점들의 공통점

객체를 새로 생성하는 동시에 동일한 자료형의 객체로 초기화해야 합니다.
-> 메모리공간이 할당되면서 동시에 초기화!

 

* 복사생성자 정의 생략 시 자동으로 디폴트복사생성자가 삽입됩니다. 매개변수로 전달되는 객체의 멤버변수를 선언되는 객체의 멤버변수로 자동으로 복사하나 문제점이 있습니다. (얕은복사, 메모리릭)

* 객체의 깊은복사 시 객체를 인자로 받는 참조형 매개변수를 가진 생성자를 추가 (디폴트 복사생성자를 오버로딩)
- 생성자의 내부에서는 멤버 대 멤버 복사를 진행하는 코드를 넣어줍니다. (초기화)

* 복사생성자와 전달인자가 하나인 생성자의 묵시적 변환이 싫으면 생성자 앞에 explicit를 추가

* 복사생성자의 매개변수는 반드시 참조형. 아니면 호출의 무한루프 발생(컴파일에러)

* 복사생성자의 매개변수는 보통 const 선언

 

 

 

728x90
728x90
블로그 이미지

coding-restaurant

코딩 맛집에 방문해주셔서 감사합니다.

,

v