목록

레이블이 CPP인 게시물을 표시합니다. 모든 게시물 표시
레이블이 CPP인 게시물을 표시합니다. 모든 게시물 표시

2019년 7월 7일 일요일

[C++] thread_local 스레드 지역 변수



thread_local 키워드를 이용하여.
같은 이름을 가지지만 스레드마다 다른 전용 변수를 만들 수 있습니다.

사용 예1 전역 변수
  1. #include <iostream>
  2. #include <thread>
  3.  
  4. thread_local int abc = 1;
  5.  
  6. void func()
  7. {
  8.         std::cout << abc << '\n';
  9. }
  10.  
  11. void main()
  12. {
  13.         ++abc; //주 스레드의 abc 변수값 1 증가 ( 2)
  14.  
  15.         std::thread th(func);
  16.         th.join(); // 다른 스레드에서의 func 출력 결과 1
  17.  
  18.         func(); //주 스레드의 func 출력 결과 2
  19. }

사용 예2 지역 변수
지역변수에 thread_local 키워드를 붙인다면
static을 붙이지 않아도 static 속성이 적용됩니다.


  1. #include <iostream>
  2. #include <thread>
  3.  
  4. void func()
  5. {
  6.         thread_local int abc = 1; //thread_local static int abc = 1; 과 같음
  7.         std::cout << abc++ << '\n';
  8. }
  9.  
  10. void func2()
  11. {
  12.         func();
  13.         func();
  14. }
  15.  
  16. void main()
  17. {
  18.         std::thread th(func2);
  19.         th.join(); // 다른 스레드에서의 func2 출력 결과 1 2
  20.         func2(); //주 스레드의 func 출력 결과 1 2
  21. }



사용 예3 static 멤버 변수

  1. #include <iostream>
  2. #include <thread>
  3.  
  4. class A
  5. {
  6. public:
  7.         thread_local static int abc;
  8. };
  9. thread_local int A::abc = 1;
  10.  
  11.  
  12. void func()
  13. {
  14.         std::cout << A::abc++ << '\n';
  15. }
  16.  
  17. void func2()
  18. {
  19.         func();
  20.         func();
  21. }
  22.  
  23. void main()
  24. {
  25.         std::thread th(func2);
  26.         th.join(); // 다른 스레드에서의 func2 출력 결과 1 2
  27.         func2(); //주 스레드의 func 출력 결과 1 2
  28. }







2019년 7월 6일 토요일

[C++] boost asio TCP 비동기 에코 서버, 동기 클라이언트

boost asio aync echo server,
sync client


예제 살짝 변형해서 가져옴
클라는 quit 메시지 입력시 종료

서버

  1. #include <cstdlib>
  2. #include <iostream>
  3. #include <memory>
  4. #include <utility>
  5. #include <boost/asio.hpp>
  6.  
  7. using boost::asio::ip::tcp;
  8.  
  9. class session
  10.         : public std::enable_shared_from_this<session>
  11. {
  12. public:
  13.         session(tcp::socket socket)
  14.                : socket_(std::move(socket))
  15.         {
  16.         }
  17.  
  18.         void start()
  19.         {
  20.                do_read();
  21.         }
  22.  
  23. private:
  24.         void do_read()
  25.         {
  26.                auto self(shared_from_this());
  27.                socket_.async_read_some(boost::asio::buffer(data_, max_length),
  28.                        [this, self](boost::system::error_code ec, std::size_t length)
  29.                {
  30.                        if (!ec)
  31.                        {
  32.                               do_write(length);
  33.                        }
  34.                });
  35.         }
  36.  
  37.         void do_write(std::size_t length)
  38.         {
  39.                auto self(shared_from_this());
  40.                boost::asio::async_write(socket_, boost::asio::buffer(data_, length),
  41.                        [this, self](boost::system::error_code ec, std::size_t /*length*/)
  42.                {
  43.                        if (!ec)
  44.                        {
  45.                               do_read();
  46.                        }
  47.                });
  48.         }
  49.  
  50.         tcp::socket socket_;
  51.         enum { max_length = 1024 };
  52.         char data_[max_length];
  53. };
  54.  
  55. class server
  56. {
  57. public:
  58.         server(boost::asio::io_context& io_context, short port)
  59.                : acceptor_(io_context, tcp::endpoint(tcp::v4(), port))
  60.         {
  61.                do_accept();
  62.         }
  63.  
  64. private:
  65.         void do_accept()
  66.         {
  67.                acceptor_.async_accept(
  68.                        [this](boost::system::error_code ec, tcp::socket socket)
  69.                {
  70.                        if (!ec)
  71.                        {
  72.                               std::make_shared<session>(std::move(socket))->start();
  73.                        }
  74.  
  75.                        do_accept();
  76.                });
  77.         }
  78.  
  79.         tcp::acceptor acceptor_;
  80. };
  81.  
  82. int main()
  83. {
  84.         try
  85.         {
  86.                boost::asio::io_context io_context;
  87.  
  88.                server s(io_context, 13);
  89.  
  90.                io_context.run();
  91.         }
  92.         catch (std::exception& e)
  93.         {
  94.                std::cerr << "Exception: " << e.what() << "\n";
  95.         }
  96.  
  97.         return 0;
  98. }



클라이언트

  1. #include <cstdlib>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <boost/asio.hpp>
  5.  
  6. using boost::asio::ip::tcp;
  7.  
  8. enum { max_length = 1024 };
  9.  
  10. int main()
  11. {
  12.         try
  13.         {
  14.                boost::asio::io_context io_context;
  15.  
  16.                tcp::socket s(io_context);
  17.                tcp::resolver resolver(io_context);
  18.                boost::asio::connect(s, resolver.resolve("127.0.0.1", "13"));
  19.                for (;;)
  20.                {
  21.                        std::cout << "Enter message: ";
  22.                        char request[max_length];
  23.                        std::cin.getline(request, max_length);
  24.                        if (strcmp(request, "quit") == 0)
  25.                        {
  26.                               break;
  27.                        }
  28.  
  29.                        size_t request_length = std::strlen(request);
  30.                        boost::asio::write(s, boost::asio::buffer(request, request_length));
  31.  
  32.                        char reply[max_length];
  33.                        size_t reply_length = boost::asio::read(s,
  34.                               boost::asio::buffer(reply, request_length));
  35.                        std::cout << "Reply is: ";
  36.                        std::cout.write(reply, reply_length);
  37.                        std::cout << "\n";
  38.                }
  39.         }
  40.         catch (std::exception& e)
  41.         {
  42.                std::cerr << "Exception: " << e.what() << "\n";
  43.         }
  44.  
  45.         return 0;
  46. }

2019년 7월 4일 목요일

[C++] boost 1.70 asio TCP 비동기 데이트 타임 출력 서버

그냥 홈페이지에 나와있는 예제임

TCP 서버

  1. #include <ctime>
  2. #include <iostream>
  3. #include <string>
  4. #include <memory>
  5. #include <boost/asio.hpp>
  6. #include <boost/bind.hpp>
  7.  
  8. using boost::asio::ip::tcp;
  9.  
  10. std::string make_daytime_string()
  11. {
  12.         using namespace std;
  13.         time_t now = time(0);
  14.         return ctime(&now);
  15. }
  16.  
  17. class tcp_connection : public std::enable_shared_from_this<tcp_connection>
  18. {
  19.         tcp::socket socket_;
  20.         std::string message_;
  21. public:
  22.         using pointer = std::shared_ptr<tcp_connection>;
  23.  
  24.         static pointer create(boost::asio::io_context& io_context)
  25.         {
  26.                return pointer(new tcp_connection(io_context));
  27.         }
  28.  
  29.         tcp::socket& socket()
  30.         {
  31.                return socket_;
  32.         }
  33.  
  34.         void start()
  35.         {
  36.                message_ = make_daytime_string();
  37.                boost::asio::async_write(socket_, boost::asio::buffer(message_)
  38.                        , boost::bind(&tcp_connection::handle_write
  39.                               , shared_from_this()
  40.                               , boost::asio::placeholders::error
  41.                               , boost::asio::placeholders::bytes_transferred));
  42.         }
  43. private:
  44.         tcp_connection(boost::asio::io_context& io_context) : socket_(io_context){}
  45.         void handle_write(const boost::system::error_code&, size_t) {}
  46. };
  47.  
  48. class tcp_server
  49. {
  50.         boost::asio::io_context& io_context_;
  51.         tcp::acceptor acceptor_;
  52. public:
  53.         tcp_server(boost::asio::io_context& io_context)
  54.                : io_context_(io_context)
  55.                , acceptor_(io_context, tcp::endpoint(tcp::v4(), 13))
  56.         {
  57.                start_accept();
  58.         }
  59.  
  60. private:
  61.         void start_accept()
  62.         {
  63.                tcp_connection::pointer new_connection = tcp_connection::create(io_context_);
  64.                acceptor_.async_accept(new_connection->socket(),
  65.                        boost::bind(&tcp_server::handle_accept, this, new_connection,
  66.                               boost::asio::placeholders::error));
  67.         }
  68.         void handle_accept(tcp_connection::pointer new_connection,
  69.                const boost::system::error_code& error)
  70.         {
  71.                if (!error)
  72.                {
  73.                        new_connection->start();
  74.                }
  75.                start_accept();
  76.         }
  77. };
  78.  
  79. int main()
  80. {
  81.         try
  82.         {
  83.                boost::asio::io_context io_context;
  84.                tcp_server server(io_context);
  85.                io_context.run();
  86.         }
  87.         catch (std::exception& e)
  88.         {
  89.                std::cerr << e.what() << std::endl;
  90.         }
  91.         return 0;
  92. }



TCP 클라이언트

  1. #include <iostream>
  2. #include <array>
  3. #include <boost/asio.hpp>
  4.  
  5. using boost::asio::ip::tcp;
  6.  
  7. int main()
  8. {
  9.         try
  10.         {
  11.                boost::asio::io_service io_service;
  12.                tcp::resolver resolver(io_service);
  13.                tcp::resolver::query query("127.0.0.1", "daytime");
  14.                tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
  15.                tcp::socket socket(io_service);
  16.                boost::asio::connect(socket, endpoint_iterator);
  17.                for (;;)
  18.                {
  19.                        std::array<char, 128> buf;
  20.                        boost::system::error_code error;
  21.  
  22.                        size_t len = socket.read_some(boost::asio::buffer(buf), error);
  23.                        if (error == boost::asio::error::eof)
  24.                               break; // Connection closed cleanly by peer.
  25.                        else if (error)
  26.                               throw boost::system::system_error(error); // Some other error.
  27.  
  28.                        std::cout.write(buf.data(), len);
  29.                }
  30.         }
  31.         catch (std::exception& e)
  32.         {
  33.                std::cerr << e.what() << std::endl;
  34.         }
  35.         return 0;
  36. }

2019년 6월 19일 수요일

[C++] nullptr, std::nullptr_t



nullptr 은 포인터 변수의 값으로 0을 전달하기 위해 C++11에서 새로 추가된 키워드입니다.
언듯 보면 대단히 쓸모없어 보이는 이 키워드는 그냥 포인터 변수에 정수 0을 대입하는것 보다 아주 약간 유용한 기능을 제공합니다.

바로 오버로딩 된 함수를 호출 시 무심코 0값을 전달하는 경우
정수형 인자를 받는 함수가 잘못 호출 될 수 있습니다.


  1. #include <string>
  2. #include <iostream>
  3.  
  4. void test(int v)
  5. {
  6.         std::cout << "call test(int)\n";
  7. }
  8.  
  9. void test(char *str)
  10. {
  11.         if (str)
  12.         {
  13.                std::cout << str << '\n';
  14.         }
  15.         else
  16.         {
  17.                std::cout << "str is null\n";
  18.         }
  19. }
  20.  
  21. int main()
  22. {
  23.         test(0);
  24.         test(nullptr);
  25. }


void test(char *str) 함수를 호출하고 str is null을 출력하고 싶은경우가 있다고 가정합니다.
무심코 0을 전달하면 void test(int v) 가 호출되버리고 맙니다.
하지만 nullptr 을 전달하면 nullptr 은 정수형으로 인식하지 않기 때문에 포인터 변수를 받는 void test(char *str)이 호출되게 됩니다.

만약 void test(int *pi) 도 있다면 어떻게 될까요?
그런 경우는 어떤것을 호출될지 모호하기 때문에 컴파일 타임 에러가 납니다.
그런 경우는 그냥 전달 전에 캐스팅 해서 어떤 함수를 호출할지 정해주어야합니다.
(int*)0 전달 또는 (int*)nullptr 전달


nullptr 을 매개변수로 전달 할 수 있는것을 보면 nullptr도 타입이 있겠죠?
auto a = nullptr; 이런식으로 작성해서 a의 타입을 확인해보면
std::nullptr_t 라는 타입이라고 나옵니다.
구조를 보려고 했는데 볼수가 없습니다. 그냥 bool, int 이런것처럼 새로운 타입입니다.

[C++] new(std::nothrow) 할당 실패시 0값 리턴 받기



new를 통한 할당이 실패할 시 std::bad_cast 예외가 아닌 null값(0)을 리턴하도록 할 수 있습니다.

다음과 같이 작성하면 됩니다.

new(std::nothrow) 타입;

using namespace std; 를 하셨다면

std:: 부분을 빼셔도 됩니다.

[C/C++] 인라인 키워드. inline, __inline, __forceinline


인라인 함수는 호출이 일어나는 위치에 인라인 함수의 실행코드를 복사하여 실행해주는 함수입니다.

인라인 함수의 장점은 일반 함수가 호출 또는 복귀할 때 필요한 명령을 줄이므로 좀 더 빠릅니다.

단점으로는 컴파일시 호출된 지점으로 코드가 복사되므로 실행 프로그램의 크기가 커집니다.

단,  함수를 인라인 화 하려면 호출하는 곳에서 해당 함수의 내용까지 모두 알고 있어야합니다. 때문에 인라인 할 함수는 헤더파일에 정의까지 다 작성하는 경우가 흔합니다.

인라인 함수에 사용되는 키워드는 다음과 같습니다.


1. inline
해당 키워드가 붙은 함수는 컴파일러의 판단에 따라 인라인 함수가 될지 결정됩니다.
함수의 내용이 거의 없는 경우 인라인 함수가 될 가능성이 높아집니다.
즉, 이 키워드가 붙어도 반드시 인라인 함수가 되는 것은 아니라는것입니다.
해당 키워드는 cpp 에서 사용 가능합니다.

2. _inline, __inline
위 inline과 동일하되, C와 C++ 모두 사용 가능합니다.
MSVC, IBM컴파일러 비표준입니다. 다른 컴파일러에서 사용 불가능 할 수 있습니다.

3. __forceinline
해당 키워드가 붙은 함수는 인라인 함수가 될수 있다면 반드시 인라인 함수가 됩니다.
인라인 함수가 될 수 없는 경우는 virtual 함수이거나 재귀함수이거나 함수 포인터를 통한 호출이거나 등.
C와 C++ 모두 사용 가능합니다.
MSVC비표준입니다. 다른 컴파일러에서 사용 불가능 할 수 있습니다.
gcc에서는 __attribute__((allways_inline)) 을 사용합니다.


사용 방식
키워드 함수형식

inline void A(){}
__forceinline void B();
멤버 함수에서도 사용 가능.


2019년 6월 15일 토요일

[C++] 특정 메모리에 대해서 생성자 수동 호출



특정 메모리에 대해서 생성자를 수동으로 호출 할 수 있습니다.

경우에 따라 위험할 수 있으니, 생성자, 소멸자 호출 시점을
잘 아시는 분만 사용하시길 권합니다.


사용 방법
new(주소) 타입(생성자 매개변수 리스트);


사용 예


  1. #include <string>
  2. #include <iostream>
  3. using namespace std;
  4. class A
  5. {
  6.         std::string str;
  7. public:
  8.         A()
  9.         {
  10.                cout << "call A()\n";
  11.         }
  12.         ~A()
  13.         {
  14.                cout << "call ~A()\n";
  15.         }
  16. };
  17. int main()
  18. {
  19.        {
  20.             char buffer[sizeof(A)]; //버퍼의 크기는 적어도 A의 크기보다 커야 문제가 발생하지 않는다.
  21.             A* a = new(buffer) A; //buffer 메모리에 대해서 생성자 수동 호출
  22.             a->~A(); //buffer A타입이 아니기 때문에 블록이 끝날 때
  23.             //A의 소멸자가 자동으로 호출되지 않으므로 사용이 끝나면 수동으로 소멸자를 호출해 주어야 함
  24.         }
  25.         {
  26.             A a;
  27.             a.~A();  // 생성자 호출 전에 기존 객체의 소멸자를 호출해 주지 않으면 메모리 릭이 일어난다.
  28.             new(&a) A; //a 주소에 A클래스 생성자 수동 호출
  29.             //a A클래스 이므로 블록이 끝날 때 ~A 가 자동으로 호출 됨
  30.         }
  31. }


실제로 STL 에서도 많이 사용되고 있습니다.
디버깅 하다보면 vector 등의 컨테이너에서 볼 수 있을 것임

2019년 6월 14일 금요일

[C++] 오버라이드(override) 키워드


C++11 부터 추가된 override 키워드는
오버라이딩을 한 함수에 붙여서 해당 함수가 오버라이딩 한 함수임을 다른 개발자에게 알리는 용도 및 오버라이딩 함수의 검증 용도로 사용됩니다.
자바를 해본 사람이라면 @Override 키워드를 생각하시면 됩니다.



사용 방법
오버라이딩 한 함수의 선언부 매개변수 리스트 뒤에.
세미콜론(;) 또는 중괄호의 시작({) 이 나타나기전에 override 라고 입력을 합니다.




부모클래스의 가상 함수와 이름 및 리턴 타입, 매개변수 리스트가 모두 똑같은 경우 별도로 virtual 을 붙이지 않아도 함수가 오버라이딩 되는데,
해당 클래스만 봐서는 함수가 오버라이딩 한 함수인지 파악이 되지 않습니다.
virtual 을 붙였다 하더라도 해당 클래스에서 새로 만들어진 함수인지, 부모클래스에 있는 함수를 오버라이딩 한 것인지 알 수 없기도 하고요.

override 키워드를 붙이면 조상클래스까지 뒤져보지 않아도 오버라이딩 되었다는것을 한 번에 알 수 있게 됩니다.

또한 앞서 검증 용도로도 사용된다고도 설명드렸는데,
함수 이름, 리턴 타입, 매개변수 리스트 중 하나라도 다르다면 오버라이딩이 실패합니다.
하지만 override 키워드를 붙이지 않았다면 컴파일러가 그냥 전혀 다른 함수로 인식하고 의도와는 다르게 문제없이 컴파일이 되버립니다.


해당 스크린샷은 고의로 오버라이딩 할 함수의 이름에 오타를 내어보았습니다. (대소문자)
override 키워드가 붙여져 있다면 다음과 같이 에러를 뿜어서 오버라이딩에 문제가 있을을 알 수있는데, override 키워드를 붙이지 않는 경우 문제없이 컴파일 되버립니다.


2019년 6월 13일 목요일

[C++] 형변환(Type casting) dynamic_cast

편의상 클래스(또는 구조체)를 그냥 클래스로 표현합니다.


dynamic_cast는 보통 부모클래스와 자식클래스간 형변환에 사용되는 캐스트 연산자로
다른 캐스팅과는 다르게 실패 검증기능이 있어서,
형변환에 실패할 시 포인터로의 캐스팅은 null값을 리턴하고,
이 포스팅에선 참조로의 캐스팅 예시 소스코드를 보여드리진 않지만,
참조로의 형변환이 실패하면 std::bad_cast 예외를 냅니다.

그리고 dynamic_cast 를 사용할 때 피연산자는 다형 클래스 형식이여야 합니다.
이게 무슨 말이냐면, virtual 함수가 하나라도 있어야 된다는 뜻입니다.
그렇지 않으면 빌드시 컴파일 타임에 오류를 뱉게 됩니다.

virtual 함수가 없을 때는 자식클래스에서 부모클래스로의 변환일때만 가능합니다.



dynamic_cast의 원리는 클래스내에는 숨겨진 값이 있습니다.
가상 함수가 있는경우 vftable 을 가르키는 포인터 변수가 숨겨져 있고,
virtual 상속을 하는 경우는 vbtable 이란것도 있죠.
dynamic_cast는 vftable 포인터의 값을 통해 캐스팅의 실패 및 성공 여부를 알아낼 수 있습니다.

vftable은 가상함수 테이블로. 가상함수가 하나라도 있는 클래스에는 가상함수테이블 포인터가 반드시 존재합니다. 가상함수 테이블은 클래스마다 다르며, 상속구조에서 다른 가상함수 테이블 포인터 주소를 바꾸어 클래스마다 다른 함수가 불리도록 오버라이딩 하는것을 가능하게 만듭니다.


*RTTI(Real Time Type Information) 옵션을 끄면 dynamic_cast 를 사용할 수 없습니다.


1. 사용 예

1)  다형성을 위해 자손클래스 들을 모아 놓은 리스트에서 원래의 타입을 알아내려고 할 때

물론 원래의 타입을 알아내기 위해서라면 virtual 함수를 만들어 고유의 타입 ID를 리턴하도록 오버라이딩 하고
타입 아이디에 따라 타입을 알아내면 되긴 합니다.
하지만 상속할 클래스가 내가 만든 클래스가 아니라면? 라이브러리에 들어있는 거라 함수를 마음대로 추가할 수 없다면? 등등의 이유로 오버라이딩을 통한 해결이 어려울 때가 있지요.


  1. #include <iostream>
  2. class Animal { virtual void f() {} };
  3. class Cat : public Animal {};
  4. class Dog : public Animal {};
  5. void main()
  6. {
  7.         Animal* animals[3] = { new Cat, new Dog, new Dog };
  8.         if (dynamic_cast<Cat*>(animals[1]))
  9.         {
  10.                std::cout << "animals[1] Cat";
  11.         }
  12.         else if (dynamic_cast<Dog*>(animals[1]))
  13.         {
  14.                std::cout << "animals[1] Dog";
  15.         }
  16.         else if (dynamic_cast<Dog*>(animals[1]))
  17.         {
  18.                std::cout << "animals[1] 은 몰라";
  19.         }
  20. }


2) 죽음의 마름모 꼴에서 한 번에 다운 캐스팅 할 때
static_cast 같은 다른 캐스팅은 불가능한데 dynamic_cast는 가능해요. vftable의 값을 보면 알 수 있거든요.
심지어 C스타일 캐스트도 한 번에 다운 캐스팅 시도하면 컴파일 타임에 오류를 내뱉습니다.
reinterpret_cast는 가능하긴 하나, 어떤 자식 기준으로 변환할지 상관하지 않고 주소 그대로 강제적인 캐스팅을
해대기 때문에 문제가 발생하는 경우가 있습니다.

3) std::any 처럼 타입 상관없이 어떤 값을 저장하는 무언가를 만들 때
any가 정말 적당한 예중 하나인것 같아서 넣어보았습니다.
std::any_cast 는 사실상 dynamic_cast 사용하여 박싱 클래스로 부터
원래의 타입을 알아내고 원래의 타입에 대한 값을 돌려주는 역할을 합니다.



2. dynamic_cast 사용 시 런타임 형변환에 실패하는 경우



1)  자식클래스가 부모 클래스를 protected 또는 private 상속 받은 경우
  이 경우는 비주얼 스튜디오에서 컴파일 타임 에러를 내어주긴 하나
  피연산자가 추론형태인 경우 (템플릿 함수내에서 템플릿 인수 이거나 람다 함수에서 auto인자)는
  문제 없이 빌드가 되고 런타임에 실패값을 줍니다.
  1. class A { virtual void f() {} };
  2. class B : private A {};
  3. void main()
  4. {
  5.         B b;
  6.         auto Cast = [](auto * p) {return dynamic_cast<A*>(p); }; //캐스팅 실패. 0값 리턴 
  7.         auto result = Cast(&b);
  8. }



2) 피연산자 원래의 타입보다 자손 타입으로 캐스팅 할 때
   조상 타입으로 캐스팅 하는것은 가능합니다. (목표 조상까지 모두 public 상속 받아야 함)

  1. class A { virtual void f() {} };
  2. class B : public A {};
  3. void main()
  4. {
  5.         A a;
  6.         auto result = dynamic_cast<B*>(&a); //캐스팅 실패. 0값 리턴 
  7. }



3) 조상은 같지만 줄기가 다른 클래스로의 변환

  1. class A { virtual void f() {} };
  2. class B : public A {};
  3. class C : public A {};
  4. void main()
  5. {
  6.         B b;
  7.         auto result = dynamic_cast<C*>(&b); //캐스팅 실패. 0값 리턴 
  8. }


4) 전혀 다른 클래스로의 변환
     이건 컴파일 타임에 에러를 내어 줄 수 있을 법한데, 그냥 빌드 되네요.
  1. class A { virtual void f() {} };
  2. class B : public A {};
  3. class C {};
  4. void main()
  5. {
  6.         B b;
  7.         auto result = dynamic_cast<C*>(&b); //캐스팅 실패. 0값 리턴 
  8. }




5) 죽음의 마름모꼴 상속에서 겹치는 조상 클래스로의 변환
   이것도 그냥 쓰면 컴파일 타임에 모호하도고 에러뜨는데, 추론형태로 전달하면 빌드됩니다.
   실패 이유는 어떤조상의 클래스인지 모호해서 그렇습니다. 여기서는 B::A 인지 C::A인지 모호해서.


  1. class A { virtual void f() {} };
  2. class B : public A {};
  3. class C : public A {};
  4. class D : public B, public C {};
  5. void main()
  6. {
  7.         D d;
  8.         auto Cast = [](auto * p) {return dynamic_cast<A*>(p); }; // 모호. 캐스팅 실패. 0값 리턴 
  9.         auto result = Cast(&d);
  10.         result = Cast(static_cast<B*>(&d)); //대체 방법. 어떤 조상의 A클래스인지 알 수 있게 
  11.                                              //조상포인터로 먼저 캐스팅
  12. }

A에서 D로 조상 클래스에서 한 번에 캐스팅 하는 것은 가능합니다.
static_cast 같은 다른 캐스팅은 불가능한데 dynamic_cast는 가능해요. vftable의 값을 보면 알 수 있거든요.



목록