精华内容
下载资源
问答
  • 近期正在做在Ubuntu环境下将C++程序封装成动态库文件和静态库文件,期间不知道掉了多少坑,在这里写下来以免忘记工作是将实现MTCNN的C++源代码封装成动态库文件和静态库文件,原先在github上找到了一个依据opencv和...

    近期现学现做一个在Ubuntu环境下将C++程序封装成动态.so库文件和静态.a库文件的小项目, 期间不知道掉了多少坑,所以在这里记录下来与诸君共勉

    一、静态库和动态库

    本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行,库可分成静态库和动态库(共享库),在Windows系统下,分别对应着xx.lib和xx.dll文件,在linux系统下,分别是xx.a和xx.so文件。

    1.静态库

    静态库的命名形式是libname.a.静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。它的优点是,编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进可执行文件了。同样它的不足,如果静态函数库改变了,那么你的程序必须重新编译,而且体积也较大。

    2.动态库

    动态库名字一般是libname.so.相对于静态函数库,共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小由于函数库没有被整合进你的程序,而是程序运行时动态申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。而且如果多个应用程序都要使用同一函数库,动态库就非常适合,可以减少应用程序的体积。

    静态库和动态库的主要区别在于:静态库是在程序编译时被链接到目标代码中,而动态库是在程序运行时才被载入。

    二、生成动态库和静态库

    一开始找的MTCNN的源代码是依赖于opencv和openblas环境,说起配置环境又是一把辛酸泪,在这里不再赘述,源码中头文件和cpp文件数量不多,所以采用的是用g++的方式生成库文件,可是在测试的时候,能够在没有配置opencv的环境下直接调用程序所需要的库文件,但是却不能在没有openblas的环境下调用libopenblas库文件,所以当时就放弃了这种方案。

    1.用g++方式分别创建静态和动态库文件

    在linux系统下,是用命令ar处理A.o目标文件生成静态库文件,需要指令如下:

    1.g++ -c  A.cpp  -o A.o
    2.ar -cr libA.a A.o
    3.ar -r libABC.a  *.o

    第一条指令是编译A.cpp 生成 A.o文件

    第二条指令是生成静态库文件,在-cr后面的参数就是库文件的名字

    第三条指令是将目录下的所有的.o文件合并生成静态库

    在linux下编译时,通过 -shared 参数可以生成动态库.so文件,如下:

    g++ -shared -fPIC -o libA.so A.o

    -shared 该选项指定生成动态连接库,不用该标志外部程序无法连接。相当于一个可执行文件
    -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的,所以动态载入时是通过代码拷贝的方式来满足不同
    进程的需要,而不能达到真 正代码段共享的目的。

    2.使用cmake方式创建静态库和动态库文件

    很幸运地是,我们又找到了一个不依赖任何第三方库的C++源程序代码,可是此源码的头文件和CPP文件的数量巨大,而且代码具有层次感,其中还有子文件夹,所以在这个时候,用Cmake方式创建库文件是很高效间接的手段。

    采用out-of-source编译的方式,按照习惯,建立一个build目录,将源程序文件放入build目录下,并在build目录下编写CMakeLists.txt,这个文件是cmake的构建定义文件,文件名是大小写相关的。为了能同时生成动态库文件和静态库文件,CMakeLists.txt文件中的相应内容如下:

    1.add_library(name SHARED source1, source2, ..., sourceN)
    2.add_library(name_static STATIC source1, source2, ... , sourceN)
    3.set_target_properties(name_static PROPERTIES OUTPUT_NAME "name")
    4.set_target_properties(name_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    5.set_target_properties(name PROPERTIES CLEAN_DIRECT_OUTPUT 1)
    6.set_target_properties(name PROPERTIES VERSION 1.2 SOVERSION 1)
    7.install(TARGETS name name_static 
              LIBRARY DESTINATION lib
              ARCHIVE DESTINATION lib)
    8.install(DIRECTORY ${titile_H} DESTINATION include/tH)

    第一条指令是生成动态库(扩展名为.so),类型关键字是SHARED,并不需要写全libname.so,只需要填写name即可,cmake系统会自动生成libname.so。

    第二条指令是在支持动态库的基础上为工程添加一个静态库,因为静态库和动态库同名时,构建静态库的指令是无效的,所以把上面的name修改为name_static,就可以构建一个libname_static的静态库;然而我们需要的是名字相同的静态库和动态库,因为target的唯一性,所以就不能通过add_library指令实现,所以用到第三条指令

    第三条指令是为了能够同时得到libname.so/libname.a两个库文件,但是因为cmake在构建一个新的target时,会尝试清理掉具有相同命名的库文件,所以,在构建libname.a的时候会将libname.so库文件清理掉,因此需要再次使用set_target_properties定义的CLEAN_DIRECT_OUTPUT属性,如第四条和第五条指令所示,至此,我们再次进行构建,就会发现在目录中同时生成libname.so动态库文件和libname.a静态库文件

    第六条指令是因为按照规则,动态库是应当包含一个版本号的, 为了实现动态库版本号,仍然需要使用SET_TARGET_PROPERTIES指令,其中VERSON指代动态库版本,SOVERSION指代API版本。

    第七条指令是将动态库和静态库文件安装到系统目录,才能够真正地让其他人开发使用,我们将库文件安装到<prefix>/lib目录下

    第八条指令是将头文件安装到<prefix>/include/tH目录中。

    在终端进入build目录的上级目录,输入命令行,命令如下:

    cmake build

    make

    sudo make install

    至此,我们就可以将头文件和库文件分别安装到系统目录/usr/local/include/tH/和usr/local/lib中了。

    三、外部引用动态库和静态库和头文件

    构建和安装动态库和静态库之后,为了测试库文件是否被外部调用,需要编写源文件main.cpp进行函数调用测试。同样,我们还是使用cmake方式进行编译

    3.1 外部引用静态库文件

    1.INCLUDE_DIRECTORIES(头文件在系统中的位置)
    2.ADD_EXECUTABLE(main source/main.cpp)
    3.TARGET_LINK_LIBRARIES(main libfaceDetection.a)

    第一条指令是引用头文件搜索路径

    第二条指令的作用是生成一个名为main的可执行文件

    第三条指令是位target添加静态库

    3.2 外部引用动态库文件

    因为编译安装将动态库安装到/usr/local/lib目录下,对于动态库的外部引用有些麻烦,稍后补上





    展开全文
  • 如果不知道应该放哪里,就都试试哪个文件夹都试试,再一个一个删除,看看哪个会影响程序运行,就是这个文件夹了 问题二:试图加载格式不正确的程序 解决办法:因为平台设置不正确,看看你的平台是什么,...

    先看文章最后一句话

    1.问题一:无法加载DLL,找不到指定的模块

    解决办法:把你用的dll放在你自己程序的启动路径下。比如bin/debug/....或者x64/debug/.....

    如果不知道应该放哪里,就都试试哪个文件夹都试试,再一个一个删除,看看哪个会影响程序运行,就是这个文件夹了

     

    问题二:试图加载格式不正确的程序

    解决办法:因为平台设置不正确,看看你的平台是什么,跟编译dll的平台一样吗?

    核对:(C#配置和C++)代码配置

     如果发现自己编译的opencv的c++代码是x64的而c#程序不能用x64,那就只能重新编译一个win32的x86或者win32的win32程序。注意编译dll前需要配置win32也就是x86版本的opencv,具体配置方法和x64的配置方法一样,只是要选择x86的文件夹下的bin进行配置,然后再编译dll(参考配置x64配置自己的x86)。请注意:有的opencv自带x86版本,如opencv2.4.13,有的只有x64版本,需要自己用Cmake编译,还要注意配置时候自己VS选择的版本。然后将引用dll的c#程序加一句话,如下:

    [DllImport("PackageDll.dll", EntryPoint = "CutPic", CallingConvention = CallingConvention.Cdecl)]
    public static extern bool CutPic(string path);

    C#默认调用的是__Stdcall

     

    问题三:外部组件发生异常

    解决办法:单步调式,看是不是参数传错了,看是不是找不到要处理的文件,看是不是C++和C#的传参值有问题(如C#用string类型,C++的形参要用char *)

    问题四:.NETFramework,Version不匹配问题

    解决办法:在启动程序的app.config文件中加入运行时动态变化.NETFramework,Version版本,如:

    <startup useLegacyV2RuntimeActivationPolicy="true">
      <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
      <supportedRuntime version="v2.0.50727"/>
    </startup>

    x86版本示例:https://download.csdn.net/download/qq_40155090/12004885 

     

    切记:代码执行的时候,要重新生成解决方案,每次改东西都重新生成,即使改传入的参数,也要重新生成解决方案,很重要、很重要、很重要 

     

    展开全文
  • C++程序设计学习继承、封装、多态的例子。代码简单明了,清晰明确,用龙与人战斗的场景,通过控制台程序,展示了三大特征的最基本应用,循序渐进。适合初学者借鉴学习。
  • C++ 数据封装教程

    2011-03-20 15:37:30
    C++ 数据封装 结构体 详细介绍有关结构体和数据封装的具体内容 内附课件详解程序
  • 主要介绍了利用C++内核对象封装的类,程序只能运行单个实例,可防止多次启动,大家参考使用吧
  • c++作为面向对象的程序语言,有三大特性:封装性、继承性、多态性。 此篇说明封装性:什么是封装?自己的理解就是将很多同类事物(比如狗类)的共同特性(名字、颜色、跑、叫、吃)封装起来,然后遇到一个该类事物...

    c++作为面向对象的程序语言,有三大特性:封装性、继承性、多态性。

    此篇说明封装性:什么是封装?自己的理解就是将很多同类事物(比如狗类)的共同特性(名字、颜色、跑、叫、吃)封装起来,然后遇到一个该类事物(一只具体的狗)时,就可以直接使用从该类事物封装好的这些特性。用类和对象来讲,就是:类封装了所有同类对象的一些共同特性(每个对象都有的属性(数据成员)和方法(成员函数));实例化一个类的对象后,该对象就会有这些共同特性。

    这样的好处有:1.更安全,因为封装的这些特性不再是直接暴露在全局或main里面了,有public、protected、private之分,访问需要权限。2.更方便,实例化一个对象后直接调用它的公有特性就可以完成很多事情,比如定义一个狗类,有公有方法run(),那实例化两个狗dog1,dog2,让它们跑,就直接调用dog1.run(),dog2.run()就行了,不用重复写具体怎么跑的代码;也许普通的全局函数也可以实现,但是要在全局函数中使用dog的其它特性还是很麻烦复杂,而且函数的具体的操作是暴露在全局的,很不安全。3.真正是面向对象的思想,是从一个对象出发,根据对象特性进行操作。大大提高了代码的复用性。

    类与结构体区别:1.结构体内一般不会有函数2.结构体里没有public、protected、private这些区别,不安全,没有实现真正有效的封装。3.还是面向过程4.结构体也不存在继承、多态的性质





    展开全文
  • C++ 数据封装 所有的 C++ 程序都有以下两个基本要素: 程序语句(代码):这是程序中执行动作的部分,它们被称为函数。 程序数据:数据是程序的信息,会受到程序函数的影响。 封装是面向对象编程中的把数据和操作...
  • 控制屏幕保护程序API函数的C++封装by 郭世龙简 介 前几天在codeproject上看到了一篇关于用C#封装控制的屏幕保护程序的文章,觉的很有用于是决定将其改装成C++封装以供C++程序员使用。这个类提供了查询屏幕保护...
    控制屏幕保护程序API函数的C++类封装
    by 郭世龙
    简 介
          前几天在codeproject上看到了一篇关于用C#封装控制的屏幕保护程序的文章,觉的很有用于是决定将其改装成C++类封装以供C++程序员使用。这个类提供了查询屏幕保护程序信息的函数,包括是否启用、是否正在运行、查询和设置屏保等待时间、强制关闭屏幕保护程序等函数。user32.dll 动态链接库提供的SystemParametersInfo()API函数(需要包含头文件Windows.h)提供了对屏幕保护程序控制的功能。
      
    函数介绍
    • bool GetScreenSaverActive( )                  —— 判断屏幕保护程序是否开启,如果开启则返回true否则返回false
    • void SetScreenSaverActive(int Active)    —— 传递参数1来开启屏幕保护程序, 传递0来关闭屏幕保护程序
    • int GetScreenSaverTimeout( )                  —— 返回当前屏幕保护程序等待时间设置,以秒位单位
    • void SetScreenSaverTimeout(int Value)    —— 设置屏幕保护程序等待时间,以秒位单位
    • bool GetScreenSaverRunning( )          —— 判断当前屏幕保护程序是否正在运行,是则返回ture否则返回false
    • void KillScreenSaver( )                          —— 强制结束屏幕保护
      
    封装代码
          使用时,拷贝代码到程序中,引入这个 ScreenSaverCtrl类文件即可。
     
    头文件:
    //ScreenSaverCtrl.h
    #pragma once
    #include "Windows.h"
    /*   //静态链接
    #pragma comment(lib,"User32.lib")   //在link时,链接到User32.lib文件

    extern "C"
    {
       WINUSERAPI BOOL WINAPI SystemParametersInfoW(__in UINT uiAction,__in UINT uiParam,__inout_opt PVOID pvParam,__in UINT fWinIni);
      WINUSERAPI BOOL WINAPI SystemParametersInfoA(__in UINT uiAction,__in UINT uiParam,__inout_opt PVOID pvParam,__in UINT fWinIni);
      WINUSERAPI BOOL WINAPI PostMessageA(__in_opt HWND hWnd,__in UINT Msg, __in WPARAM wParam,__in LPARAM lParam);
      WINUSERAPI HDESK WINAPI OpenDesktopA(__in LPCSTR lpszDesktop,__in DWORD dwFlags,__in BOOL fInherit,__in ACCESS_MASK dwDesiredAccess);
      WINUSERAPI BOOL WINAPI CloseDesktop(__in HDESK hDesktop);
      WINUSERAPI BOOL WINAPI EnumDesktopWindows( __in_opt HDESK hDesktop, __in WNDENUMPROC lpfn, __in LPARAM lParam);
      WINUSERAPI BOOL WINAPI IsWindowVisible(__in HWND hWnd);
      WINUSERAPI HWND WINAPI GetForegroundWindow(VOID);
      WINUSERAPI BOOL WINAPI EnumDesktopWindows(__in_opt HDESK hDesktop,__in WNDENUMPROC lpfn,__in LPARAM lParam);
     
    }
    */
    //BOOL CALLBACK KillScreenSaverFunc(HWND hWnd,LPARAM lParam);
    class ScreenSaverCtrl
    {
     public:
      ScreenSaverCtrl(void);
      static bool GetScreenSaverActive();
      static void SetScreenSaverActive(int Active);
      static int GetScreenSaverTimeout();
      static void SetScreenSaverTimeout(int Value);
      static bool GetScreenSaverRunning();
      static void KillScreenSaver();
     private:
      static BOOL CALLBACK KillScreenSaverFunc(HWND hWnd,LPARAM lParam);
      
     public:
      ~ScreenSaverCtrl(void);
    };
     
    实现文件:
     
    //ScreenSaverCtrl.cpp
    #include "ScreenSaverCtrl.h"
     
    /*
    BOOL CALLBACK KillScreenSaverFunc(HWND hWnd,LPARAM lParam)    //注意回调函数不能为普通成员函数,但可为静态成员函数
    {
      if( IsWindowVisible(hWnd) ) PostMessage( hWnd, WM_CLOSE, 0, 0 );
      return true;
    }
    */
     
    ScreenSaverCtrl::ScreenSaverCtrl(void
    {
     
    }
     
    bool ScreenSaverCtrl::GetScreenSaverActive( )
    {
      BOOL isActive = FALSE;  
    //一定是BOOL而不是bool否则运行时错误
      SystemParametersInfo(SPI_GETSCREENSAVEACTIVE,0,&isActive, 0);
      return isActive;
    }
     
    void ScreenSaverCtrl::SetScreenSaverActive( int Active )
    {
      int nullVar = 0;
      SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,Active, &nullVar, SPIF_SENDWININICHANGE );
    }
     
    int ScreenSaverCtrl::GetScreenSaverTimeout( )
    {
      int value = 0;
      SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0,&value, 0 );
      return value;
    }
      
    void ScreenSaverCtrl::SetScreenSaverTimeout(int Value )
    {
      int nullVar = 0;
      SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT,Value, &nullVar,SPIF_SENDWININICHANGE );
    }
      
    bool ScreenSaverCtrl::GetScreenSaverRunning( )
    {
      BOOL isRunning = FALSE;
      SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0,&isRunning, 0 );
      return isRunning;
    }
      
    void ScreenSaverCtrl:: KillScreenSaver( )
    {
      HDESK hDesktop = OpenDesktop(TEXT("Screen-saver"), 0,false,DESKTOP_READOBJECTS | DESKTOP_WRITEOBJECTS);
      if( hDesktop != NULL)
      {
         EnumDesktopWindows(hDesktop,KillScreenSaverFunc,0);
         CloseDesktop( hDesktop );
      }
      else
      {
         PostMessage( GetForegroundWindow( ), WM_CLOSE, 0, 0 );
      }
    }
     
      //注意回调函数不能为非静态成员函数,因为其有隐含参数this 而静态成员函数没有this指针
    BOOL ScreenSaverCtrl::KillScreenSaverFunc(HWND hWnd,LPARAM lParam)   
    {
      if( IsWindowVisible(hWnd) ) PostMessage( hWnd, WM_CLOSE, 0, 0 );
      return true;
    }
     
    ScreenSaverCtrl::~ScreenSaverCtrl(void)
    {

    }
     
    测试程序
     
    编译运行环境
                   操作系统:Windows XP SP2
                   编译器:VS2005
     
    测试程序界面
      测试程序界面
    测试程序下载
     
    展开全文
  • C++封装

    千次阅读 2019-01-24 22:20:06
    封装 : 在类和对象阶段,我们只研究类的封装特性,那什么是封装呢? 封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来和对象进行 交互。 封装本质上是一种管理:我们如何管理...
  • C++封装程序的模块化)

    千次阅读 2016-03-22 18:19:00
    封装:对类的封装 对函数的封装—在函数或者类的外部留下交互接口,将函数或者类的内部封装,通过从交互接口传递参数进行运算(函数执行需要的变量) 例子: 被封装的计算长方形面积的函数(函数封装)—— int area...
  • rs232 rs485 串口程序c++封装 功能丰富齐全的串口操作 内有操作说明 很好的一个串口操作程序 使用方法如下: 1.自己重新写一个串口操作源文件cmd.c或者cmd.cpp 2.在cmd.c或者cmd.cpp中定义 头文件#include ...
  • C++接口封装

    千次阅读 2018-04-17 16:14:41
    在产品开发过程中,我们经常会需要对外提供DLL的接口,这种接口可以在产品开是设计好的,也可能是在基本功能开发完成进行封装的,这里将介绍一种比较基本常用的封装方法,供初学者参考。欢迎提出好的改进方式。先提...
  • 昨天,算是实现了阶段性小胜利,将C++程序封装成了DLL文件,再用C++程序调用DLL并实现其功能,达到了给代码加密的功能。 好了,废话少说,步入正题!!! 这只是一个简单的例子,意在摸清DLL文件生成和调用的整个...
  • 摘 要:本文介绍了ADO访问数据库的基本过程,给出了一种在Visual C++封装ADO访问数据库类的方法。 关键词:封装;ADO;Visual C 1 引言 在过去几年中,微软公司相继推出了几种数据访问技术,先是DAO(Data Access...
  • C++封装

    千次阅读 2018-08-15 13:13:32
    相比于C语言,C++中提供了一种非常实用并且也非常常用的方法——封装封装是指将某些具有相同属性或性质的变量等归纳在同一处,已达到使用和构造方便。C语言中也提供了一个类似于封装的关键词——struct,但该...
  • C++第二季--02(C++数据封装

    千次阅读 2020-10-10 17:31:41
    所有的C++程序都有以下两个基本要素: 程序语句(代码):这是程序中执行动作的部分,它们被称为函数。 程序数据:数据是程序的信息,会受到程序函数的影响。 封装是面向对象编程中的把数据和操作数据的函数绑定在...
  • 我喜欢C++的速度,我喜欢python的简洁,我相信只用C++,python就可以解决99.99%的问题,那么如何让它们交互呢,这里仅说明如何将C++的代码接口封装使得python可以调用c++。一个简单的应用我写了一个分词器,我希望能...
  • 第 2 章 C++类 及其对象的封装性 本章主要内容 2.1 类的声明和对象定义 2.2 类的成员函数 2.3 对象成员的引用 2.4 类的封装性和信息隐蔽 2.5 构造函数和析构函数 2.6 对象指针 2.7 动态存储 2.1类的声明和对象定义 ...
  • 关于c++程序以c语言的形式封装成非托管dll

    千次阅读 多人点赞 2020-06-18 13:08:41
    前段时间做了嵌入式系统大作业,其中由于我们的workstation端采用的是c++语言编写的,而winform的gui界面是以c语言的形式编写的,因此我们要将workstation里的函数以c语言的形式封装成dll,进而可以在winform中调用...
  • GLSL程序对象的C++封装

    千次阅读 2016-11-20 15:53:09
    在OpenGL的shader编程中,最常用的可能就是程序对象了,GLSL的程序对象的创建、加载shader等步骤都是固定的,如果每次都写同样的代码,觉得十分浪费时间,所以现在就将我在Shader学习过程中自己封装的GLSLProgram类...
  • c++DLL封装DLL问题

    千次阅读 2016-08-19 16:48:58
    封装的DLL是阿里的消息队列C++的SDK,阿里只能静态加载,配置麻烦,所以封装使用。 在编写测试过程中出过很多问题,因为我是第一次封装,小问题就不做记录,几个稍微大的问题,第一个封装完成调用运行的时候报错,...
  • 可以用,c++做的,帧的封装和解析程序,代码有注释。
  • C++ 封装 & 信息隐藏

    千次阅读 多人点赞 2021-05-02 14:02:39
    C++ 封装 & 信息隐藏简介
  • 一般c++项目封装成动态链接库dll

    千次阅读 2018-12-27 14:46:51
    一般c++项目封装成动态链接库dll 更改函数声明 在函数声明前加上 extern &quot;C&quot; _declspec(dllexport) 比如: extern &quot;C&quot; _declspec(dllexport) int testIntf(int num1, int...
  • 浅析C++封装

    千次阅读 2012-09-10 22:38:10
    封装性是C++的入门特性,要想学习C++语言,封装性是首先要掌握的。下面我们进入正题: 一、 类与对象 早在本系列第一节课(理解程序中的数据)的时候讲述过数据类型与数据的区别和联系当时得出的结论如下: Ø ...
  • C++封装的含义和简单实现

    千次阅读 2020-04-29 14:20:18
    其实封装并不是编程中的一个思想,对于很多领域来说都...而对于 C++ 来说也是这样,借由数据类型也可以实现封装。这样做的好处就是对外屏蔽了功能实现,对内开放了数据权限。 C++ 中的类和对象是经由 C 中的 struc...
  • 一、C++程序封装成dll文件 1、新建动态链接库项目 生成的文件包含以下文件: 其中,targetver.h可以声明要导出的dll中函数名;Dll1.cpp实现要导出的函数功能。 targetver.h内容如下: #pragma once // ...
  • C++ 封装 详解

    2019-03-31 20:54:25
    封装 封装的意义:  封装的意义在于保护或者防止代码(数据)被我们无意中破坏。在面向对象程序设计中数据被看作是一个中心的元素并且和使用它的函数结合的很密切,从而保护它不被其它的函数意外的修改。 1. 保护...
  • C++封装zlib库

    万次阅读 多人点赞 2021-01-20 21:23:19
    C++对zlib库进行简单封装什么是zlib库如何下载zlib库源代码如何安装zlib库合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容...
  • 从C语言的角度出发理解C++封装继承和多态 在学习C++面对对象程序设计的时候,会把C++类的使用和C结构体的使用作比较。我们都知道C++是C语言的继承,而C++最明显的特征就是面对对象,那么C++是如何继承的,这是我...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 208,346
精华内容 83,338
关键字:

c++程序封装

c++ 订阅