diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index d1cfe5032a7..2491e656491 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -860,6 +860,21 @@ "redirect_url": "/cpp/build/reference/running-nmake", "redirect_document_id": false }, + { + "source_path": "docs/build/manifest-generation-in-visual-studio.md", + "redirect_url": "/cpp/build/understanding-manifest-generation-for-c-cpp-programs#manifest-generation-in-visual-studio", + "redirect_document_id": false + }, + { + "source_path": "docs/build/manifest-generation-at-the-command-line.md", + "redirect_url": "/cpp/build/understanding-manifest-generation-for-c-cpp-programs#manifest-generation-at-the-command-line", + "redirect_document_id": false + }, + { + "source_path": "docs/build/how-to-embed-a-manifest-inside-a-c-cpp-application.md", + "redirect_url": "/cpp/build/understanding-manifest-generation-for-c-cpp-programs#how-to-embed-a-manifest-inside-a-c-cpp-application", + "redirect_document_id": false + }, { "source_path": "docs/build/unwind-data-for-exception-handling-debugger-support.md", "redirect_url": "/cpp/build/exception-handling-x64", diff --git a/docs/build/how-to-embed-a-manifest-inside-a-c-cpp-application.md b/docs/build/how-to-embed-a-manifest-inside-a-c-cpp-application.md deleted file mode 100644 index cb98e6dabb6..00000000000 --- a/docs/build/how-to-embed-a-manifest-inside-a-c-cpp-application.md +++ /dev/null @@ -1,254 +0,0 @@ ---- -description: "Learn more about: How to: Embed a Manifest Inside a C/C++ Application" -title: "How to: Embed a Manifest Inside a C/C++ Application" -ms.date: "05/06/2019" -helpviewer_keywords: ["manifests [C++]", "embedding manifests", "makefiles, updating to embed manifest"] -ms.assetid: ec0bac69-2fdc-466c-ab0d-710a22974e5d ---- -# How to: Embed a Manifest Inside a C/C++ Application - -We recommended that you embed the manifest of your application or library inside the final binary because this guarantees correct runtime behavior in most scenarios. By default, Visual Studio tries to embed the manifest when it builds a project. For more information, see [Manifest Generation in Visual Studio](manifest-generation-in-visual-studio.md). However, if you build your application by using nmake, you have to make some changes to the makefile. This section shows how to change the makefiles so that it automatically embeds the manifest inside the final binary. - -## Two approaches - -There are two ways to embed the manifest inside an application or library. - -- If you are not doing an incremental build you can directly embed the manifest using a command line similar to the following as a post-build step: - - ```cmd - mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;1 - ``` - - or - - ```cmd - mt.exe -manifest MyLibrary.dll.manifest -outputresource:MyLibrary.dll;2 - ``` - - Use 1 for an EXE and 2 for a DLL. - -- If you are doing an incremental build, use the following steps: - - - Link the binary to generate the MyApp.exe.manifest file. - - - Convert the manifest to a resource file. - - - Re-link (incrementally) to embed the manifest resource into the binary. - -The following examples show how to change makefiles to incorporate both techniques. - -## Makefiles (Before) - -Consider the nmake script for MyApp.exe, a simple application built from one file: - -``` -# build MyApp.exe -!if "$(DEBUG)" == "1" -CPPFLAGS=$(CPPFLAGS) /MDd -LFLAGS=$(LFLAGS) /INCREMENTAL -!else -CPPFLAGS=$(CPPFLAGS) /MD -!endif - -MyApp.exe : MyApp.obj - link $** /out:$@ $(LFLAGS) - -MyApp.obj : MyApp.cpp - -clean : - del MyApp.obj MyApp.exe -``` - -If this script is run unchanged with Visual Studio, it successfully creates MyApp.exe. It also creates the external manifest file MyApp.exe.manifest, for use by the operating system to load dependent assemblies at runtime. - -The nmake script for MyLibrary.dll looks very similar: - -``` -# build MyLibrary.dll -!if "$(DEBUG)" == "1" -CPPFLAGS=$(CPPFLAGS) /MDd -LFLAGS=$(LFLAGS) /DLL /INCREMENTAL - -!else -CPPFLAGS=$(CPPFLAGS) /MD -LFLAGS=$(LFLAGS) /DLL - -!endif - -MyLibrary.dll : MyLibrary.obj - link $** /out:$@ $(LFLAGS) - -MyLibrary.obj : MyLibrary.cpp - -clean : - del MyLibrary.obj MyLibrary.dll -``` - -## Makefiles (After) - -To build with embedded manifests you have to make four small changes to the original makefiles. For the MyApp.exe makefile: - -``` -# build MyApp.exe -!include makefile.inc -#^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.) - -!if "$(DEBUG)" == "1" -CPPFLAGS=$(CPPFLAGS) /MDd -LFLAGS=$(LFLAGS) /INCREMENTAL -!else -CPPFLAGS=$(CPPFLAGS) /MD -!endif - -MyApp.exe : MyApp.obj - link $** /out:$@ $(LFLAGS) - $(_VC_MANIFEST_EMBED_EXE) -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2 - -MyApp.obj : MyApp.cpp - -clean : - del MyApp.obj MyApp.exe - $(_VC_MANIFEST_CLEAN) -#^^^^^^^^^^^^^^^^^^^^^^^^ Change #3 - -!include makefile.targ.inc -#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.) -``` - -For the MyLibrary.dll makefile: - -``` -# build MyLibrary.dll -!include makefile.inc -#^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.) - -!if "$(DEBUG)" == "1" -CPPFLAGS=$(CPPFLAGS) /MDd -LFLAGS=$(LFLAGS) /DLL /INCREMENTAL - -!else -CPPFLAGS=$(CPPFLAGS) /MD -LFLAGS=$(LFLAGS) /DLL - -!endif - -MyLibrary.dll : MyLibrary.obj - link $** /out:$@ $(LFLAGS) - $(_VC_MANIFEST_EMBED_DLL) -#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2. - -MyLibrary.obj : MyLibrary.cpp - -clean : - del MyLibrary.obj MyLibrary.dll - $(_VC_MANIFEST_CLEAN) -#^^^^^^^^^^^^^^^^^^^^^^^^ Change #3. - -!include makefile.targ.inc -#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.) -``` - -The makefiles now include two files that do the real work, makefile.inc and makefile.targ.inc. - -Create makefile.inc and copy the following into it: - -``` -# makefile.inc -- Include this file into existing makefile at the very top. - -# _VC_MANIFEST_INC specifies whether build is incremental (1 - incremental). -# _VC_MANIFEST_BASENAME specifies name of a temporary resource file. - -!if "$(DEBUG)" == "1" -CPPFLAGS=$(CPPFLAGS) /MDd -LFLAGS=$(LFLAGS) /INCREMENTAL -_VC_MANIFEST_INC=1 -_VC_MANIFEST_BASENAME=__VC90.Debug - -!else -CPPFLAGS=$(CPPFLAGS) /MD -_VC_MANIFEST_INC=0 -_VC_MANIFEST_BASENAME=__VC90 - -!endif - -#################################################### -# Specifying name of temporary resource file used only in incremental builds: - -!if "$(_VC_MANIFEST_INC)" == "1" -_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res -!else -_VC_MANIFEST_AUTO_RES= -!endif - -#################################################### -# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE: - -!if "$(_VC_MANIFEST_INC)" == "1" - -#MT_SPECIAL_RETURN=1090650113 -#MT_SPECIAL_SWITCH=-notify_resource_update -MT_SPECIAL_RETURN=0 -MT_SPECIAL_SWITCH= -_VC_MANIFEST_EMBED_EXE= \ -if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \ -if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \ -rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \ -link $** /out:$@ $(LFLAGS) - -!else - -_VC_MANIFEST_EMBED_EXE= \ -if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1 - -!endif - -#################################################### -# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily: - -!if "$(_VC_MANIFEST_INC)" == "1" - -_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \ - $(_VC_MANIFEST_BASENAME).auto.rc \ - $(_VC_MANIFEST_BASENAME).auto.manifest - -!else - -_VC_MANIFEST_CLEAN= - -!endif - -# End of makefile.inc -#################################################### -``` - -Now create **makefile.targ.inc** and copy the following into it: - -``` -# makefile.targ.inc - include this at the very bottom of the existing makefile - -#################################################### -# Commands to generate initial empty manifest file and the RC file -# that references it, and for generating the .res file: - -$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc - -$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest - type <<$@ -#include -1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest" -<< KEEP - -$(_VC_MANIFEST_BASENAME).auto.manifest : - type <<$@ - - - -<< KEEP - -# end of makefile.targ.inc -``` - -## See also - -[Understanding Manifest Generation for C/C++ Programs](understanding-manifest-generation-for-c-cpp-programs.md) diff --git a/docs/build/manifest-generation-at-the-command-line.md b/docs/build/manifest-generation-at-the-command-line.md deleted file mode 100644 index e7acf1a1d64..00000000000 --- a/docs/build/manifest-generation-at-the-command-line.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -description: "Learn more about: Manifest Generation at the Command Line" -title: "Manifest Generation at the Command Line" -ms.date: "11/04/2016" -helpviewer_keywords: ["manifests [C++]", "manifest tool (mt.exe)"] -ms.assetid: fc2ff255-82b1-4c44-af76-8405c5850292 ---- -# Manifest Generation at the Command Line - -When building C/C++ applications from the command line using nmake or similar tools, the manifest is generated after the linker has processed all object files and built the final binary. The linker collects assembly information stored in the object files and combines this information into a final manifest file. By default the linker will generate a file named *binary_name*.*extension*.manifest to describe the final binary. The linker does not embed a manifest file inside the binary and can only generate a manifest as an external file. There are several ways to embed a manifest inside the final binary, such as using the [Manifest Tool (mt.exe)](/windows/win32/sbscs/mt-exe) or compiling the manifest into a resource file. It is important to keep in mind that specific rules have to be followed when embedding a manifest inside the final binary to enable such features as incremental linking, signing, and edit and continue. These and other options are discussed in [How to: Embed a Manifest Inside a C/C++ Application](how-to-embed-a-manifest-inside-a-c-cpp-application.md) when building on the command line. - -## See also - -[Manifests](/windows/win32/sbscs/manifests)
-[/INCREMENTAL (Link Incrementally)](reference/incremental-link-incrementally.md)
-[Strong Name Assemblies (Assembly Signing) (C++/CLI)](../dotnet/strong-name-assemblies-assembly-signing-cpp-cli.md)
-[Edit and Continue](/visualstudio/debugger/edit-and-continue)
-[Understanding Manifest Generation for C/C++ Programs](understanding-manifest-generation-for-c-cpp-programs.md)
diff --git a/docs/build/manifest-generation-in-visual-studio.md b/docs/build/manifest-generation-in-visual-studio.md deleted file mode 100644 index e8c943d4a3c..00000000000 --- a/docs/build/manifest-generation-in-visual-studio.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -description: "Learn more about: Manifest Generation in Visual Studio" -title: "Manifest Generation in Visual Studio" -ms.date: "11/04/2016" -helpviewer_keywords: ["manifests [C++]"] -ms.assetid: 0af60aa9-d223-42cd-8426-b3fc543a2a81 ---- -# Manifest Generation in Visual Studio - -Generation of a manifest file for a particular project can be controlled in the project **Property Pages** dialog. On the **Configuration Properties** tab, click **Linker**, then **Manifest File**, then **Generate Manifest**. By default the project properties of new projects are set to generate a manifest file. However it is possible to disable generation of the manifest for a project using the **Generate Manifest** property of the project. When this property is set to **Yes**, the manifest for this project is generated. Otherwise the linker ignores assembly information when resolving dependencies of the application code, and does not generate the manifest. - -The build system in Visual Studio allows the manifest to be embedded in the final binary application file, or generated as an external file. This behavior is controlled by the **Embed Manifest** option in the **Project Properties** dialog. To set this property, open the **Manifest Tool** node, then select **Input and Output**. If the manifest is not embedded, it is generated as an external file and saved in the same directory as the final binary. If the manifest is embedded, Visual Studio embeds the final manifests using the following process: - -1. After the source code is compiled to object files, the linker collects dependent assembly information. While linking the final binary, the linker generates an intermediate manifest that is used later to generate the final manifest. - -1. After the intermediate manifest and linking are finished, the manifest tool will be executed to merge a final manifest and save it as an external file. - -1. The project build system then detects whether the manifest generated by the manifest tool contains different information than the manifest already embedded in the binary. - -1. If the manifest embedded in the binary is different from the manifest generated by the manifest tool, or the binary does not contain an embedded manifest, Visual Studio will invoke the linker one more time to embed the external manifest file inside the binary as a resource. - -1. If the manifest embedded in the binary is the same as the manifest generated by the manifest tool, the build will continue to the next build steps. - -The manifest is embedded inside the final binary as a text resource and it can be viewed by opening the final binary as a file in Visual Studio. To ensure that the manifest points to the correct libraries, follow the steps described in [Understanding the Dependencies of a Visual C++ Application](../windows/understanding-the-dependencies-of-a-visual-cpp-application.md) or follow the suggestions described in the [Troubleshooting](troubleshooting-c-cpp-isolated-applications-and-side-by-side-assemblies.md) section. - -## See also - -[Understanding Manifest Generation for C/C++ Programs](understanding-manifest-generation-for-c-cpp-programs.md) diff --git a/docs/build/toc.yml b/docs/build/toc.yml index ae2e11b2a89..d754e8bc37a 100644 --- a/docs/build/toc.yml +++ b/docs/build/toc.yml @@ -285,16 +285,7 @@ items: - name: "How to: Build isolated applications to consume COM components" href: ../build/how-to-build-isolated-applications-to-consume-com-components.md - name: Understanding manifest generation for C/C++ programs - expanded: false - items: - - name: Understanding manifest generation for C/C++ programs - href: ../build/understanding-manifest-generation-for-c-cpp-programs.md - - name: Manifest generation in Visual Studio - href: ../build/manifest-generation-in-visual-studio.md - - name: Manifest generation at the command line - href: ../build/manifest-generation-at-the-command-line.md - - name: "How to: Embed a manifest inside a C/C++ application" - href: ../build/how-to-embed-a-manifest-inside-a-c-cpp-application.md + href: ../build/understanding-manifest-generation-for-c-cpp-programs.md - name: Troubleshooting C/C++ isolated applications and side-by-side assemblies href: ../build/troubleshooting-c-cpp-isolated-applications-and-side-by-side-assemblies.md - name: Configure MSVC for 64-bit, x64 targets diff --git a/docs/build/understanding-manifest-generation-for-c-cpp-programs.md b/docs/build/understanding-manifest-generation-for-c-cpp-programs.md index 412ec261863..9caa9820971 100644 --- a/docs/build/understanding-manifest-generation-for-c-cpp-programs.md +++ b/docs/build/understanding-manifest-generation-for-c-cpp-programs.md @@ -1,19 +1,292 @@ --- -description: "Learn more about: Understanding Manifest Generation for C/C++ Programs" -title: "Understanding Manifest Generation for C/C++ Programs" -ms.date: "11/04/2016" +description: "Learn more about: Understanding manifest generation for C/C++ programs" +title: "Understanding manifest generation for C/C++ programs" +ms.date: 06/10/2022 helpviewer_keywords: ["manifests [C++]"] ms.assetid: a1f24221-5b09-4824-be48-92eae5644b53 --- -# Understanding Manifest Generation for C/C++ Programs +# Understanding manifest generation for C/C++ programs -A [manifest](/windows/win32/sbscs/manifests) is an XML document that can be an external XML file or a resource embedded inside an application or an assembly. The manifest of an [isolated application](/windows/win32/SbsCs/isolated-applications) is used to manage the names and versions of shared side-by-side assemblies to which the application should bind at run time. The manifest of a side-by-side assembly specifies its dependencies on names, versions, resources, and other assemblies. +A [manifest](/windows/win32/sbscs/manifests) is an XML document that uniquely identifies an assembly. It contains information used for binding and activation, such as COM classes, interfaces, and type libraries. A manifest can be an external XML file or a resource embedded inside an application or an assembly. The manifest of an [isolated application](/windows/win32/SbsCs/isolated-applications) is used to manage the names and versions of shared side-by-side assemblies the application should bind to at run time. The manifest of a side-by-side assembly specifies its dependencies on names, versions, resources, and other assemblies. -There are two ways to create a manifest for an isolated application or a side-by-side assembly. First, the author of the assembly can manually create a manifest file following rules and naming requirements. Alternatively, if a program only depends on Visual C++ assemblies such as CRT, MFC, ATL or others, then a manifest can be generated automatically by the linker. +There are two ways to create a manifest for an isolated application or a side-by-side assembly. First, the author of the assembly can manually create a manifest file by following the rules and naming requirements. For more information, see [Manifest files reference](/windows/win32/sbscs/manifest-files-reference). Alternatively, if a program only depends on MSVC assemblies such as CRT, MFC, ATL or others, then the linker can generate a manifest automatically. -The headers of Visual C++ libraries contain assembly information, and when the libraries are included in application code, this assembly information is used by the linker to form a manifest for the final binary. The linker does not embed the manifest file inside the binary, and can only generate the manifest as an external file. Having a manifest as an external file may not work for all scenarios. For example, it is recommended that private assemblies have embedded manifests. In command line builds such as those that use nmake to build code, a manifest can be embedded using the manifest tool; for more information see [Manifest Generation at the Command Line](manifest-generation-at-the-command-line.md). When building in Visual Studio, a manifest can be embedded by setting a property for the manifest tool in the **Project Properties** dialog; see [Manifest Generation in Visual Studio](manifest-generation-in-visual-studio.md). +The headers of MSVC libraries contain assembly information, and when the libraries are included in application code, this assembly information is used by the linker to form a manifest for the final binary. By default, the linker doesn't embed the manifest file inside the binary. Having a manifest as an external file may not work for all scenarios. For example, it's recommended that private assemblies have embedded manifests. In command line builds such as ones that use NMAKE to build code, you can use the [`/MANIFEST:EMBED`](./reference/manifest-create-side-by-side-assembly-manifest.md) linker option to embed the manifest. Alternatively, a manifest can be embedded using the manifest tool. For more information, see [Manifest generation at the command line](#manifest-generation-at-the-command-line). When you build in Visual Studio, a manifest can be embedded by setting a property for the manifest tool in the **Project Properties** dialog, as described in the next section. + +## Manifest generation in Visual Studio + +You can tell Visual Studio to generate a manifest file for a particular project in the project's **Property Pages** dialog. Under **Configuration Properties**, select **Linker** > **Manifest File** > **Generate Manifest**. By default, the project properties of new projects are set to generate a manifest file. However it's possible to disable generation of the manifest for a project by using the **Generate Manifest** property of the project. When this property is set to **Yes**, the manifest for the project is generated. Otherwise the linker ignores assembly information when resolving dependencies of the application code, and doesn't generate the manifest. + +The build system in Visual Studio allows the manifest to be embedded in the final binary application file, or generated as an external file. This behavior is controlled by the **Embed Manifest** option in the **Project Properties** dialog. To set this property, open the **Manifest Tool** node, then select **Input and Output**. If the manifest isn't embedded, it's generated as an external file and saved in the same directory as the final binary. If the manifest is embedded, Visual Studio embeds the final manifests using the following process: + +1. After the source code is compiled to object files, the linker collects dependent assembly information. While it links the final binary, the linker generates an intermediate manifest that's used later to generate the final manifest. + +1. After the intermediate manifest and linking are finished, the manifest tool merges a final manifest and saves it as an external file. + +1. The project build system then detects whether the manifest generated by the manifest tool contains different information than the manifest already embedded in the binary. + +1. If the manifest embedded in the binary is different from the manifest generated by the manifest tool, or the binary doesn't contain an embedded manifest, Visual Studio invokes the linker one more time to embed the external manifest file inside the binary as a resource. + +1. If the manifest embedded in the binary is the same as the manifest generated by the manifest tool, the build continues to the next build steps. + +The manifest is embedded inside the final binary as a text resource. You can view it by opening the final binary as a file in Visual Studio. To ensure that the manifest points to the correct libraries, follow the steps described in [Understanding the dependencies of a Visual C++ application](../windows/understanding-the-dependencies-of-a-visual-cpp-application.md). Or, follow the suggestions described in the [Troubleshooting](troubleshooting-c-cpp-isolated-applications-and-side-by-side-assemblies.md) article. + +## Manifest generation at the command line + +When you build C/C++ applications from the command line using NMAKE or similar tools, the manifest is generated after the linker has processed all object files and built the final binary. The linker collects assembly information stored in the object files and combines this information into a final manifest file. By default, the linker generates a file named *`..manifest`* to describe the final binary. The linker can embed a manifest file inside the binary by specifying the [`/MANIFEST:EMBED`](./reference/manifest-create-side-by-side-assembly-manifest.md) linker option. + +There are several other ways to embed a manifest inside the final binary, such as using the [Manifest tool (`mt.exe`)](/windows/win32/sbscs/mt-exe) or compiling the manifest into a resource file. You must follow specific rules when you embed a manifest to enable features such as incremental linking, signing, and Edit and Continue. These rules and other options are discussed in the next section. + +## How to embed a manifest inside a C/C++ application + +We recommended that you embed the manifest of your application or library inside the final binary. This approach guarantees correct runtime behavior in most scenarios. By default, Visual Studio tries to embed the manifest when it builds a project. However, if you build your application by using NMAKE, you have to make some changes to the makefile. This section shows how to change the makefiles so that it automatically embeds the manifest inside the final binary. + +### Two approaches + +There are two ways to embed the manifest inside an application or library. + +1. If you aren't doing an incremental build, you can directly embed the manifest using a command line similar to the following as a post-build step: + + ```cmd + mt.exe -manifest MyApp.exe.manifest -outputresource:MyApp.exe;1 + ``` + + or + + ```cmd + mt.exe -manifest MyLibrary.dll.manifest -outputresource:MyLibrary.dll;2 + ``` + + Use 1 for an EXE and 2 for a DLL. + +1. If you're doing an incremental build, use the following steps: + + - Link the binary to generate the *`MyApp.exe.manifest`* file. + + - Convert the manifest to a resource file. + + - Relink (incrementally) to embed the manifest resource into the binary. + +The following examples show how to change makefiles to incorporate both techniques. + +### Makefiles (Before) + +Consider the NMAKE script for *`MyApp.exe`*, a simple application built from one file: + +```makefile +# build MyApp.exe +!if "$(DEBUG)" == "1" +CPPFLAGS=$(CPPFLAGS) /MDd +LFLAGS=$(LFLAGS) /INCREMENTAL +!else +CPPFLAGS=$(CPPFLAGS) /MD +!endif + +MyApp.exe : MyApp.obj + link $** /out:$@ $(LFLAGS) + +MyApp.obj : MyApp.cpp + +clean : + del MyApp.obj MyApp.exe +``` + +If this script is run unchanged with Visual Studio, it successfully creates *`MyApp.exe`*. It also creates the external manifest file *`MyApp.exe.manifest`*, for use by the operating system to load dependent assemblies at runtime. + +The NMAKE script for *`MyLibrary.dll`* looks similar: + +```makefile +# build MyLibrary.dll +!if "$(DEBUG)" == "1" +CPPFLAGS=$(CPPFLAGS) /MDd +LFLAGS=$(LFLAGS) /DLL /INCREMENTAL + +!else +CPPFLAGS=$(CPPFLAGS) /MD +LFLAGS=$(LFLAGS) /DLL + +!endif + +MyLibrary.dll : MyLibrary.obj + link $** /out:$@ $(LFLAGS) + +MyLibrary.obj : MyLibrary.cpp + +clean : + del MyLibrary.obj MyLibrary.dll +``` + +### Makefiles (After) + +To build with embedded manifests, you have to make four small changes to the original makefiles. For the *`MyApp.exe`* makefile: + +```makefile +# build MyApp.exe +!include makefile.inc +#^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.) + +!if "$(DEBUG)" == "1" +CPPFLAGS=$(CPPFLAGS) /MDd +LFLAGS=$(LFLAGS) /INCREMENTAL +!else +CPPFLAGS=$(CPPFLAGS) /MD +!endif + +MyApp.exe : MyApp.obj + link $** /out:$@ $(LFLAGS) + $(_VC_MANIFEST_EMBED_EXE) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2 + +MyApp.obj : MyApp.cpp + +clean : + del MyApp.obj MyApp.exe + $(_VC_MANIFEST_CLEAN) +#^^^^^^^^^^^^^^^^^^^^^^^^ Change #3 + +!include makefile.target.inc +#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.) +``` + +For the MyLibrary.dll makefile: + +```makefile +# build MyLibrary.dll +!include makefile.inc +#^^^^^^^^^^^^^^^^^^^^ Change #1. (Add full path if necessary.) + +!if "$(DEBUG)" == "1" +CPPFLAGS=$(CPPFLAGS) /MDd +LFLAGS=$(LFLAGS) /DLL /INCREMENTAL + +!else +CPPFLAGS=$(CPPFLAGS) /MD +LFLAGS=$(LFLAGS) /DLL + +!endif + +MyLibrary.dll : MyLibrary.obj + link $** /out:$@ $(LFLAGS) + $(_VC_MANIFEST_EMBED_DLL) +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Change #2. + +MyLibrary.obj : MyLibrary.cpp + +clean : + del MyLibrary.obj MyLibrary.dll + $(_VC_MANIFEST_CLEAN) +#^^^^^^^^^^^^^^^^^^^^^^^^ Change #3. + +!include makefile.target.inc +#^^^^^^^^^^^^^^^^^^^^^^^^^ Change #4. (Add full path if necessary.) +``` + +The makefiles now include two files that do the real work,*` makefile.inc`* and *`makefile.target.inc`*. + +Create *`makefile.inc`* and copy the following content into it: + +```makefile +# makefile.inc -- Include this file into existing makefile at the very top. + +# _VC_MANIFEST_INC specifies whether build is incremental (1 - incremental). +# _VC_MANIFEST_BASENAME specifies name of a temporary resource file. + +!if "$(DEBUG)" == "1" +CPPFLAGS=$(CPPFLAGS) /MDd +LFLAGS=$(LFLAGS) /INCREMENTAL +_VC_MANIFEST_INC=1 +_VC_MANIFEST_BASENAME=__VC90.Debug + +!else +CPPFLAGS=$(CPPFLAGS) /MD +_VC_MANIFEST_INC=0 +_VC_MANIFEST_BASENAME=__VC90 + +!endif + +#################################################### +# Specifying name of temporary resource file used only in incremental builds: + +!if "$(_VC_MANIFEST_INC)" == "1" +_VC_MANIFEST_AUTO_RES=$(_VC_MANIFEST_BASENAME).auto.res +!else +_VC_MANIFEST_AUTO_RES= +!endif + +#################################################### +# _VC_MANIFEST_EMBED_EXE - command to embed manifest in EXE: + +!if "$(_VC_MANIFEST_INC)" == "1" + +#MT_SPECIAL_RETURN=1090650113 +#MT_SPECIAL_SWITCH=-notify_resource_update +MT_SPECIAL_RETURN=0 +MT_SPECIAL_SWITCH= +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -out:$(_VC_MANIFEST_BASENAME).auto.manifest $(MT_SPECIAL_SWITCH) & \ +if "%ERRORLEVEL%" == "$(MT_SPECIAL_RETURN)" \ +rc /r $(_VC_MANIFEST_BASENAME).auto.rc & \ +link $** /out:$@ $(LFLAGS) + +!else + +_VC_MANIFEST_EMBED_EXE= \ +if exist $@.manifest mt.exe -manifest $@.manifest -outputresource:$@;1 + +!endif + +#################################################### +# _VC_MANIFEST_CLEAN - command to clean resources files generated temporarily: + +!if "$(_VC_MANIFEST_INC)" == "1" + +_VC_MANIFEST_CLEAN=-del $(_VC_MANIFEST_BASENAME).auto.res \ + $(_VC_MANIFEST_BASENAME).auto.rc \ + $(_VC_MANIFEST_BASENAME).auto.manifest + +!else + +_VC_MANIFEST_CLEAN= + +!endif + +# End of makefile.inc +#################################################### +``` + +Now create *`makefile.target.inc`* and copy the following content into it: + +```makefile +# makefile.target.inc - include this at the very bottom of the existing makefile + +#################################################### +# Commands to generate initial empty manifest file and the RC file +# that references it, and for generating the .res file: + +$(_VC_MANIFEST_BASENAME).auto.res : $(_VC_MANIFEST_BASENAME).auto.rc + +$(_VC_MANIFEST_BASENAME).auto.rc : $(_VC_MANIFEST_BASENAME).auto.manifest + type <<$@ +#include +1RT_MANIFEST"$(_VC_MANIFEST_BASENAME).auto.manifest" +<< KEEP + +$(_VC_MANIFEST_BASENAME).auto.manifest : + type <<$@ + + + +<< KEEP + +# end of makefile.target.inc +``` ## See also -[Concepts of Isolated Applications and Side-by-side Assemblies](concepts-of-isolated-applications-and-side-by-side-assemblies.md)
-[Building C/C++ Isolated Applications and Side-by-side Assemblies](building-c-cpp-isolated-applications-and-side-by-side-assemblies.md) +[Building C/C++ isolated applications and side-by-side assemblies](building-c-cpp-isolated-applications-and-side-by-side-assemblies.md)\ +[Concepts of isolated applications and side-by-side assemblies](concepts-of-isolated-applications-and-side-by-side-assemblies.md)\ +[Troubleshooting C/C++ isolated applications and side-by-side assemblies](troubleshooting-c-cpp-isolated-applications-and-side-by-side-assemblies.md)\ +[`/INCREMENTAL` (Link incrementally)](./reference/incremental-link-incrementally.md)\ +[`/MANIFEST` (Create side-by-side assembly manifest)](./reference/manifest-create-side-by-side-assembly-manifest.md)\ +[Strong Name assemblies (Assembly signing) (C++/CLI)](../dotnet/strong-name-assemblies-assembly-signing-cpp-cli.md)\ +[Edit and Continue](/visualstudio/debugger/edit-and-continue) diff --git a/docs/cpp/function-overloading.md b/docs/cpp/function-overloading.md index becb4d2864f..fb75c9f7f39 100644 --- a/docs/cpp/function-overloading.md +++ b/docs/cpp/function-overloading.md @@ -1,34 +1,34 @@ --- description: "Learn more about: Function Overloading" title: "Function Overloading" -ms.date: "03/27/2019" +ms.date: 06/10/2022 helpviewer_keywords: ["function overloading [C++], about function overloading", "function overloading", "declaring functions [C++], overloading"] ms.assetid: 3c9884cb-1d5e-42e8-9a49-6f46141f929e --- # Function Overloading -C++ allows specification of more than one function of the same name in the same scope. These functions are called *overloaded* functions. Overloaded functions enable you to supply different semantics for a function, depending on the types and number of arguments. +C++ lets you specify more than one function of the same name in the same scope. These functions are called *overloaded* functions, or *overloads*. Overloaded functions enable you to supply different semantics for a function, depending on the types and number of its arguments. -For example, a `print` function that takes a `std::string` argument might perform very different tasks than one that takes an argument of type **`double`**. Overloading saves you from having to use names such as `print_string` or `print_double`. At compile time, the compiler chooses which overload to use based on the type of arguments passed in by the caller. If you call `print(42.0)`, then the `void print(double d)` function will be invoked. If you call `print("hello world")`, then the `void print(std::string)` overload will be invoked. +For example, consider a `print` function that takes a `std::string` argument. This function might perform very different tasks than a function that takes an argument of type **`double`**. Overloading saves you from having to use names such as `print_string` or `print_double`. At compile time, the compiler chooses which overload to use based on the types and number of arguments passed in by the caller. If you call `print(42.0)`, then the `void print(double d)` function is invoked. If you call `print("hello world")`, then the `void print(std::string)` overload is invoked. -You can overload both member functions and non-member functions. The following table shows what parts of a function declaration C++ uses to differentiate between groups of functions with the same name in the same scope. +You can overload both member functions and free functions. The following table shows which parts of a function declaration C++ uses to differentiate between groups of functions with the same name in the same scope. ### Overloading Considerations -|Function Declaration Element|Used for Overloading?| -|----------------------------------|---------------------------| -|Function return type|No| -|Number of arguments|Yes| -|Type of arguments|Yes| -|Presence or absence of ellipsis|Yes| -|Use of **`typedef`** names|No| -|Unspecified array bounds|No| -|**`const`** or **`volatile`**|Yes, when applied to entire function| -|[Ref-qualifiers](#ref-qualifiers)|Yes| +| Function declaration element | Used for overloading? | +|--|--| +| Function return type | No | +| Number of arguments | Yes | +| Type of arguments | Yes | +| Presence or absence of ellipsis | Yes | +| Use of **`typedef`** names | No | +| Unspecified array bounds | No | +| **`const`** or **`volatile`** | Yes, when applied to entire function | +| Reference qualifiers (**`&`** and **`&&`**) | Yes | ## Example -The following example illustrates how overloading can be used. +The following example illustrates how you can use function overloads: ```cpp // function_overloading.cpp @@ -103,15 +103,15 @@ int print(double dvalue, int prec) } ``` -The preceding code shows overloading of the `print` function in file scope. +The preceding code shows overloads of the `print` function in file scope. The default argument isn't considered part of the function type. Therefore, it's not used in selecting overloaded functions. Two functions that differ only in their default arguments are considered multiple definitions rather than overloaded functions. Default arguments can't be supplied for overloaded operators. -## Argument Matching +## Argument matching -Overloaded functions are selected for the best match of function declarations in the current scope to the arguments supplied in the function call. If a suitable function is found, that function is called. "Suitable" in this context means either: +The compiler selects which overloaded function to invoke based on the best match among the function declarations in the current scope to the arguments supplied in the function call. If a suitable function is found, that function is called. "Suitable" in this context means either: - An exact match was found. @@ -121,13 +121,13 @@ Overloaded functions are selected for the best match of function declarations in - A standard conversion to the desired argument type exists. -- A user-defined conversion (either conversion operator or constructor) to the desired argument type exists. +- A user-defined conversion (either a conversion operator or a constructor) to the desired argument type exists. - Arguments represented by an ellipsis were found. The compiler creates a set of candidate functions for each argument. Candidate functions are functions in which the actual argument in that position can be converted to the type of the formal argument. -A set of "best matching functions" is built for each argument, and the selected function is the intersection of all the sets. If the intersection contains more than one function, the overloading is ambiguous and generates an error. The function that is eventually selected is always a better match than every other function in the group for at least one argument. If there's no clear winner, the function call generates an error. +A set of "best matching functions" is built for each argument, and the selected function is the intersection of all the sets. If the intersection contains more than one function, the overloading is ambiguous and generates an error. The function that's eventually selected is always a better match than every other function in the group for at least one argument. If there's no clear winner, the function call generates a compiler error. Consider the following declarations (the functions are marked `Variant 1`, `Variant 2`, and `Variant 3`, for identification in the following discussion): @@ -147,12 +147,12 @@ F1 = Add( F2, 23 ); The preceding statement builds two sets: -|Set 1: Candidate Functions That Have First Argument of Type Fraction|Set 2: Candidate Functions Whose Second Argument Can Be Converted to Type **`int`**| -|--------------------------------------------------------------------------|-----------------------------------------------------------------------------------| -|Variant 1|Variant 1 (**`int`** can be converted to **`long`** using a standard conversion)| -|Variant 3|| +| Set 1: Candidate functions that have first argument of type `Fraction` | Set 2: Candidate functions whose second argument can be converted to type **`int`** | +|--|--| +| Variant 1 | Variant 1 (**`int`** can be converted to **`long`** using a standard conversion) | +| Variant 3 | | -Functions in Set 2 are functions for which there are implicit conversions from actual parameter type to formal parameter type, and among such functions there's a function for which the "cost" of converting the actual parameter type to its formal parameter type is the smallest. +Functions in Set 2 are functions that have implicit conversions from the actual parameter type to the formal parameter type. One of those functions has the smallest "cost" to convert the actual parameter type to its corresponding formal parameter type. The intersection of these two sets is Variant 1. An example of an ambiguous function call is: @@ -170,16 +170,16 @@ Because the intersection of these two sets is empty, the compiler generates an e For argument matching, a function with *n* default arguments is treated as *n*+1 separate functions, each with a different number of arguments. -The ellipsis (...) acts as a wildcard; it matches any actual argument. It can lead to many ambiguous sets, if you don't design your overloaded function sets with extreme care. +The ellipsis (`...`) acts as a wildcard; it matches any actual argument. It can lead to many ambiguous sets, if you don't design your overloaded function sets with extreme care. > [!NOTE] -> Ambiguity of overloaded functions can't be determined until a function call is encountered. At that point, the sets are built for each argument in the function call, and you can determine whether an unambiguous overload exists. This means that ambiguities can remain in your code until they are evoked by a particular function call. +> Ambiguity of overloaded functions can't be determined until a function call is encountered. At that point, the sets are built for each argument in the function call, and you can determine whether an unambiguous overload exists. This means that ambiguities can remain in your code until they're evoked by a particular function call. ## Argument Type Differences -Overloaded functions differentiate between argument types that take different initializers. Therefore, an argument of a given type and a reference to that type are considered the same for the purposes of overloading. They are considered the same because they take the same initializers. For example, `max( double, double )` is considered the same as `max( double &, double & )`. Declaring two such functions causes an error. +Overloaded functions differentiate between argument types that take different initializers. Therefore, an argument of a given type and a reference to that type are considered the same for the purposes of overloading. They're considered the same because they take the same initializers. For example, `max( double, double )` is considered the same as `max( double &, double & )`. Declaring two such functions causes an error. -For the same reason, function arguments of a type modified by **`const`** or **`volatile`** are not treated differently than the base type for the purposes of overloading. +For the same reason, function arguments of a type modified by **`const`** or **`volatile`** aren't treated differently than the base type for the purposes of overloading. However, the function overloading mechanism can distinguish between references that are qualified by **`const`** and **`volatile`** and references to the base type. It makes code such as the following possible: @@ -225,44 +225,44 @@ Pointers to **`const`** and **`volatile`** objects are also considered different When the compiler tries to match actual arguments against the arguments in function declarations, it can supply standard or user-defined conversions to obtain the correct type if no exact match can be found. The application of conversions is subject to these rules: -- Sequences of conversions that contain more than one user-defined conversion are not considered. +- Sequences of conversions that contain more than one user-defined conversion aren't considered. -- Sequences of conversions that can be shortened by removing intermediate conversions are not considered. +- Sequences of conversions that can be shortened by removing intermediate conversions aren't considered. -The resultant sequence of conversions, if any, is called the best matching sequence. There are several ways to convert an object of type **`int`** to type **`unsigned long`** using standard conversions (described in [Standard Conversions](../cpp/standard-conversions.md)): +The resultant sequence of conversions, if any, is called the *best matching sequence*. There are several ways to convert an object of type **`int`** to type **`unsigned long`** using standard conversions (described in [Standard conversions](../cpp/standard-conversions.md)): - Convert from **`int`** to **`long`** and then from **`long`** to **`unsigned long`**. - Convert from **`int`** to **`unsigned long`**. -The first sequence, although it achieves the desired goal, isn't the best matching sequence — a shorter sequence exists. +Although the first sequence achieves the desired goal, it isn't the best matching sequence, because a shorter sequence exists. -The following table shows a group of conversions, called trivial conversions, that have a limited effect on determining which sequence is the best matching. The instances in which trivial conversions affect choice of sequence are discussed in the list following the table. +The following table shows a group of conversions called *trivial conversions*. Trivial conversions have a limited effect on which sequence the compiler chooses as the best match. The effect of trivial conversions is described after the table. -### Trivial Conversions +### Trivial conversions -|Convert from Type|Convert to Type| -|-----------------------|---------------------| -|*type-name*|*type-name* **&**| -|*type-name* **&**|*type-name*| -|*type-name* **[ ]**|*type-name* __\*__| -|*type-name* **(** *argument-list* **)**|**(** __\*__ *type-name* **) (** *argument-list* **)**| -|*type-name*|**`const`** *type-name*| -|*type-name*|**`volatile`** *type-name*| -|*type-name* __\*__|**`const`** *type-name* __\*__| -|*type-name* __\*__|**`volatile`** *type-name* __\*__| +| Argument type | Converted type | +|--|--| +| `type-name` | `type-name&` | +| `type-name&` | `type-name` | +| `type-name[]` | `type-name*` | +| `type-name(argument-list)` | `(*type-name)(argument-list)` | +| `type-name` | `const type-name` | +| `type-name` | `volatile type-name` | +| `type-name*` | `const type-name*` | +| `type-name*` | `volatile type-name*` | The sequence in which conversions are attempted is as follows: 1. Exact match. An exact match between the types with which the function is called and the types declared in the function prototype is always the best match. Sequences of trivial conversions are classified as exact matches. However, sequences that don't make any of these conversions are considered better than sequences that convert: - - From pointer, to pointer to **`const`** (`type` \* to **`const`** `type` \*). + - From pointer, to pointer to **`const`** (`type-name*` to `const type-name*`). - - From pointer, to pointer to **`volatile`** (`type` \* to **`volatile`** `type` \*). + - From pointer, to pointer to **`volatile`** (`type-name*` to `volatile type-name*`). - - From reference, to reference to **`const`** (`type` **&** to **`const`** `type` **&**). + - From reference, to reference to **`const`** (`type-name&` to `const type-name&`). - - From reference, to reference to **`volatile`** (`type` **&** to **`volatile`** `type` **&**). + - From reference, to reference to **`volatile`** (`type-name&` to `volatile type&`). 1. Match using promotions. Any sequence not classified as an exact match that contains only integral promotions, conversions from **`float`** to **`double`**, and trivial conversions is classified as a match using promotions. Although not as good a match as any exact match, a match using promotions is better than a match using standard conversions. @@ -272,8 +272,8 @@ The sequence in which conversions are attempted is as follows: - Conversion from a pointer to a derived class, to a pointer to a base class produces a better match the closer the base class is to a direct base class. Suppose the class hierarchy is as shown in the following figure. -![Graph of preferred conversions.](../cpp/media/vc391t1.gif "Graph of preferred conversions")
-Graph showing preferred conversions +![Graph of preferred conversions.](../cpp/media/vc391t1.gif "Graph of preferred conversions")\ +Graph showing preferred conversions. Conversion from type `D*` to type `C*` is preferable to conversion from type `D*` to type `B*`. Similarly, conversion from type `D*` to type `B*` is preferable to conversion from type `D*` to type `A*`. @@ -283,16 +283,16 @@ This same rule applies to pointer-to-member conversions. Conversion from type `T The preceding rule applies only along a given path of derivation. Consider the graph shown in the following figure. -![Diagram of multiple inheritance that shows preferred conversions.](../cpp/media/vc391t2.gif)
-Multiple-inheritance graph that shows preferred conversions +![Diagram of multiple inheritance that shows preferred conversions.](../cpp/media/vc391t2.gif)\ +Multiple-inheritance graph that shows preferred conversions. Conversion from type `C*` to type `B*` is preferable to conversion from type `C*` to type `A*`. The reason is that they are on the same path, and `B*` is closer. However, conversion from type `C*` to type `D*` isn't preferable to conversion to type `A*`; there's no preference because the conversions follow different paths. -1. Match with user-defined conversions. This sequence can't be classified as an exact match, a match using promotions, or a match using standard conversions. The sequence must contain only user-defined conversions, standard conversions, or trivial conversions to be classified as a match with user-defined conversions. A match with user-defined conversions is considered a better match than a match with an ellipsis but not as good a match as a match with standard conversions. +1. Match with user-defined conversions. This sequence can't be classified as an exact match, a match using promotions, or a match using standard conversions. To be classified as a match with user-defined conversions, the sequence must only contain user-defined conversions, standard conversions, or trivial conversions. A match with user-defined conversions is considered a better match than a match with an ellipsis (`...`) but not as good a match as a match with standard conversions. 1. Match with an ellipsis. Any sequence that matches an ellipsis in the declaration is classified as a match with an ellipsis. It's considered the weakest match. -User-defined conversions are applied if no built-in promotion or conversion exists. These conversions are selected on the basis of the type of the argument being matched. Consider the following code: +User-defined conversions are applied if no built-in promotion or conversion exists. These conversions are selected based on the type of the argument being matched. Consider the following code: ```cpp // argument_matching1.cpp @@ -318,7 +318,7 @@ int main() } ``` -The available user-defined conversions for class `UDC` are from type **`int`** and type **`long`**. Therefore, the compiler considers conversions for the type of the object being matched: `UDC`. A conversion to **`int`** exists, and it is selected. +The available user-defined conversions for class `UDC` are from type **`int`** and type **`long`**. Therefore, the compiler considers conversions for the type of the object being matched: `UDC`. A conversion to **`int`** exists, and it's selected. During the process of matching arguments, standard conversions can be applied to both the argument and the result of a user-defined conversion. Therefore, the following code works: @@ -329,7 +329,7 @@ UDC udc; LogToFile( udc ); ``` -In the preceding example, the user-defined conversion, **operator long**, is invoked to convert `udc` to type **`long`**. If no user-defined conversion to type **`long`** had been defined, the conversion would have proceeded as follows: Type `UDC` would have been converted to type **`int`** using the user-defined conversion. Then the standard conversion from type **`int`** to type **`long`** would have been applied to match the argument in the declaration. +In this example, the compiler invokes a user-defined conversion, `operator long`, to convert `udc` to type **`long`**. If no user-defined conversion to type **`long`** was defined, the compiler would first convert type `UDC` to type **`int`** using the user-defined `operator int` conversion. Then it would apply the standard conversion from type **`int`** to type **`long`** to match the argument in the declaration. If any user-defined conversions are required to match an argument, the standard conversions aren't used when evaluating the best match. Even if more than one candidate function requires a user-defined conversion, the functions are considered equal. For example: @@ -366,15 +366,15 @@ Both versions of `Func` require a user-defined conversion to convert type **`int Even though the second one requires both a standard conversion and the user-defined conversion, the two conversions are still considered equal. > [!NOTE] -> User-defined conversions are considered conversion by construction or conversion by initialization (conversion function). Both methods are considered equal when considering the best match. +> User-defined conversions are considered conversion by construction or conversion by initialization. The compiler considers both methods equal when it determines the best match. ## Argument matching and the `this` pointer -Class member functions are treated differently, depending on whether they are declared as **`static`**. Because nonstatic functions have an implicit argument that supplies the **`this`** pointer, nonstatic functions are considered to have one more argument than static functions; otherwise, they are declared identically. +Class member functions are treated differently, depending on whether they're declared as **`static`**. **`static`** functions don't have an implicit argument that supplies the **`this`** pointer, so they're considered to have one less argument than regular member functions. Otherwise, they're declared identically. -These nonstatic member functions require that the implied **`this`** pointer match the object type through which the function is being called, or, for overloaded operators, they require that the first argument match the object on which the operator is being applied. (For more information about overloaded operators, see [Overloaded Operators](../cpp/operator-overloading.md).) +Member functions that aren't **`static`** require the implied **`this`** pointer to match the object type the function is being called through. Or, for overloaded operators, they require the first argument to match the object the operator is applied to. For more information about overloaded operators, see [Overloaded operators](../cpp/operator-overloading.md). -Unlike other arguments in overloaded functions, no temporary objects are introduced and no conversions are attempted when trying to match the **`this`** pointer argument. +Unlike other arguments in overloaded functions, the compiler introduces no temporary objects and attempts no conversions when trying to match the **`this`** pointer argument. When the `->` member-selection operator is used to access a member function of class `class_name`, the **`this`** pointer argument has a type of `class_name * const`. If the members are declared as **`const`** or **`volatile`**, the types are `const class_name * const` and `volatile class_name * const`, respectively. @@ -390,9 +390,9 @@ obj.name The left operand of the `->*` and `.*` (pointer to member) operators are treated the same way as the `.` and `->` (member-selection) operators with respect to argument matching. -## Ref-qualifiers on member functions +## Reference-qualifiers on member functions -Ref qualifiers make it possible to overload a member function on the basis of whether the object pointed to by **`this`** is an rvalue or an lvalue. This feature can be used to avoid unnecessary copy operations in scenarios where you choose not to provide pointer access to the data. For example, assume class `C` initializes some data in its constructor, and returns a copy of that data in member function `get_data()`. If an object of type `C` is an rvalue that is about to be destroyed, then the compiler will choose the `get_data() &&` overload, which moves the data rather than copy it. +Reference qualifiers make it possible to overload a member function based on whether the object pointed to by **`this`** is an rvalue or an lvalue. Use this feature to avoid unnecessary copy operations in scenarios where you choose not to provide pointer access to the data. For example, assume class `C` initializes some data in its constructor, and returns a copy of that data in member function `get_data()`. If an object of type `C` is an rvalue that's about to be destroyed, then the compiler chooses the `get_data() &&` overload, which moves instead of copies the data. ```cpp #include @@ -435,17 +435,17 @@ Several restrictions govern an acceptable set of overloaded functions: - Any two functions in a set of overloaded functions must have different argument lists. -- Overloading functions with argument lists of the same types, based on return type alone, is an error. +- Overloading functions that have argument lists of the same types, based on return type alone, is an error. **Microsoft Specific** -You can overload **operator new** solely on the basis of return type — specifically, on the basis of the memory-model modifier specified. + You can overload **`operator new`** based on the return type, specifically, based on the memory-model modifier specified. -**END Microsoft Specific** + **END Microsoft Specific** -- Member functions can't be overloaded solely on the basis of one being static and the other nonstatic. +- Member functions can't be overloaded solely because one is **`static`** and the other isn't **`static`**. -- **`typedef`** declarations do not define new types; they introduce synonyms for existing types. They don't affect the overloading mechanism. Consider the following code: +- **`typedef`** declarations don't define new types; they introduce synonyms for existing types. They don't affect the overloading mechanism. Consider the following code: ```cpp typedef char * PSTR; @@ -458,14 +458,14 @@ You can overload **operator new** solely on the basis of return type — specifi - Enumerated types are distinct types and can be used to distinguish between overloaded functions. -- The types "array of " and "pointer to" are considered identical for the purposes of distinguishing between overloaded functions, but only for singly dimensioned arrays. That's why these overloaded functions conflict and generate an error message: +- The types "array of" and "pointer to" are considered identical for the purposes of distinguishing between overloaded functions, but only for one-dimensional arrays. These overloaded functions conflict and generate an error message: ```cpp void Print( char *szToPrint ); void Print( char szToPrint[] ); ``` - For multiply dimensioned arrays, the second and all succeeding dimensions are considered part of the type. Therefore, they are used in distinguishing between overloaded functions: + For higher dimension arrays, the second and later dimensions are considered part of the type. They're used in distinguishing between overloaded functions: ```cpp void Print( char szToPrint[] ); @@ -475,13 +475,13 @@ You can overload **operator new** solely on the basis of return type — specifi ## Overloading, overriding, and hiding -Any two function declarations of the same name in the same scope can refer to the same function, or to two discrete functions that are overloaded. If the argument lists of the declarations contain arguments of equivalent types (as described in the previous section), the function declarations refer to the same function. Otherwise, they refer to two different functions that are selected using overloading. +Any two function declarations of the same name in the same scope can refer to the same function, or to two discrete overloaded functions. If the argument lists of the declarations contain arguments of equivalent types (as described in the previous section), the function declarations refer to the same function. Otherwise, they refer to two different functions that are selected using overloading. -Class scope is strictly observed; therefore, a function declared in a base class isn't in the same scope as a function declared in a derived class. If a function in a derived class is declared with the same name as a virtual function in the base class, the derived-class function *overrides* the base-class function. For more information, see [Virtual Functions](../cpp/virtual-functions.md). +Class scope is strictly observed. A function declared in a base class isn't in the same scope as a function declared in a derived class. If a function in a derived class is declared with the same name as a `virtual` function in the base class, the derived-class function *overrides* the base-class function. For more information, see [Virtual Functions](../cpp/virtual-functions.md). -If the base class function isn't declared as 'virtual', then the derived class function is said to *hide* it. Both overriding and hiding are distinct from overloading. +If the base class function isn't declared as `virtual`, then the derived class function is said to *hide* it. Both overriding and hiding are distinct from overloading. -Block scope is strictly observed; therefore, a function declared in file scope isn't in the same scope as a function declared locally. If a locally declared function has the same name as a function declared in file scope, the locally declared function hides the file-scoped function instead of causing overloading. For example: +Block scope is strictly observed. A function declared in file scope isn't in the same scope as a function declared locally. If a locally declared function has the same name as a function declared in file scope, the locally declared function hides the file-scoped function instead of causing overloading. For example: ```cpp // declaration_matching1.cpp @@ -496,22 +496,22 @@ void func( int i ) void func( char *sz ) { - cout << "Called locally declared func : " << sz << endl; + cout << "Called locally declared func : " << sz << endl; } int main() { - // Declare func local to main. - extern void func( char *sz ); + // Declare func local to main. + extern void func( char *sz ); - func( 3 ); // C2664 Error. func( int ) is hidden. - func( "s" ); + func( 3 ); // C2664 Error. func( int ) is hidden. + func( "s" ); } ``` The preceding code shows two definitions from the function `func`. The definition that takes an argument of type `char *` is local to `main` because of the **`extern`** statement. Therefore, the definition that takes an argument of type **`int`** is hidden, and the first call to `func` is in error. -For overloaded member functions, different versions of the function can be given different access privileges. They are still considered to be in the scope of the enclosing class and thus are overloaded functions. Consider the following code, in which the member function `Deposit` is overloaded; one version is public, the other, private. +For overloaded member functions, different versions of the function can be given different access privileges. They're still considered to be in the scope of the enclosing class and thus are overloaded functions. Consider the following code, in which the member function `Deposit` is overloaded; one version is public, the other, private. The intent of this sample is to provide an `Account` class in which a correct password is required to perform deposits. It's done by using overloading. diff --git a/docs/cpp/value-types-modern-cpp.md b/docs/cpp/value-types-modern-cpp.md index 53c23e787a3..942388464b4 100644 --- a/docs/cpp/value-types-modern-cpp.md +++ b/docs/cpp/value-types-modern-cpp.md @@ -1,13 +1,13 @@ --- description: "Learn more about: C++ classes as value types" title: "C++ classes as value types" -ms.date: "11/19/2019" +ms.date: 06/09/2022 ms.topic: "conceptual" ms.assetid: f63bb62c-60da-40d5-ac14-4366608fe260 --- # C++ classes as value types -C++ classes are, by default, value types. They can be specified as reference types, which enable polymorphic behavior to support object-oriented programming. Value types are sometimes viewed from the perspective of memory and layout control, whereas reference types are about base classes and virtual functions for polymorphic purposes. By default, value types are copyable, which means there is always a copy constructor and a copy assignment operator. For reference types, you make the class non-copyable (disable the copy constructor and copy assignment operator) and use a virtual destructor, which supports their intended polymorphism. Value types are also about the contents, which, when they are copied, always give you two independent values that can be modified separately. Reference types are about identity - what kind of object is it? For this reason, "reference types" are also referred to as "polymorphic types". +C++ classes are, by default, value types. They can be specified as reference types, which enable polymorphic behavior to support object-oriented programming. Value types are sometimes viewed from the perspective of memory and layout control, whereas reference types are about base classes and virtual functions for polymorphic purposes. By default, value types are copyable, which means there's always a copy constructor and a copy assignment operator. For reference types, you make the class non-copyable (disable the copy constructor and copy assignment operator) and use a virtual destructor, which supports their intended polymorphism. Value types are also about the contents, which, when they're copied, always give you two independent values that can be modified separately. Reference types are about identity - what kind of object is it? For this reason, "reference types" are also referred to as "polymorphic types". If you really want a reference-like type (base class, virtual functions), you need to explicitly disable copying, as shown in the `MyRefType` class in the following code. @@ -40,11 +40,11 @@ test.cpp(15) : error C2248: 'MyRefType::operator =' : cannot access private memb ## Value types and move efficiency -Copy allocation overhead is avoided due to new copy optimizations. For example, when you insert a string in the middle of a vector of strings, there will be no copy re-allocation overhead, only a move- even if it results in a grow of the vector itself. This also applies to other operations, for instance performing an add operation on two very large objects. How do you enable these value operation optimizations? In some C++ compilers, the compiler will enable this for you implicitly, much like copy constructors can be automatically generated by the compiler. However, in C++, your class will need to "opt-in" to move assignment and constructors by declaring it in your class definition. This is accomplished by using the double ampersand (&&) rvalue reference in the appropriate member function declarations and defining move constructor and move assignment methods. You also need to insert the correct code to "steal the guts" out of the source object. +Copy allocation overhead is avoided due to new copy optimizations. For example, when you insert a string in the middle of a vector of strings, there's no copy reallocation overhead, only a move, even if it results in growth of the vector itself. These optimizations also apply to other operations: for instance, performing an add operation on two huge objects. How do you enable these value operation optimizations? The compiler enables them for you implicitly, much like copy constructors can be automatically generated by the compiler. However, your class has to "opt-in" to move assignments and move constructors by declaring them in your class definition. Move uses the double ampersand (&&) rvalue reference in the appropriate member function declarations and defining move constructor and move assignment methods. You also need to insert the correct code to "steal the guts" out of the source object. -How do you decide if you need move enabled? If you already know you need copy construction enabled, you probably want move enabled if it can be cheaper than a deep copy. However, if you know you need move support, it doesn't necessarily mean you want copy enabled. This latter case would be called a "move-only type". An example already in the standard library is `unique_ptr`. As a side note, the old `auto_ptr` is deprecated, and was replaced by `unique_ptr` precisely due to the lack of move semantics support in the previous version of C++. +How do you decide if you need to enable move operations? If you already know you need to enable copy construction, you probably want to enable move construction, too, especially if it's cheaper than a deep copy. However, if you know you need move support, it doesn't necessarily mean you want to enable copy operations. This latter case would be called a "move-only type". An example already in the standard library is `unique_ptr`. As a side note, the old `auto_ptr` is deprecated, and was replaced by `unique_ptr` precisely due to the lack of move semantics support in the previous version of C++. -By using move semantics you can return-by-value or insert-in-middle. Move is an optimization of copy. There is need for heap allocation as a workaround. Consider the following pseudocode: +By using move semantics, you can return-by-value or insert-in-middle. Move is an optimization of copy. There's no need for heap allocation as a workaround. Consider the following pseudocode: ```cpp #include