楼主: 13052042009
270 0

[其他] C++:部分基础语法知识点 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

80%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0.0177
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
30 点
帖子
2
精华
0
在线时间
0 小时
注册时间
2018-12-17
最后登录
2018-12-17

楼主
13052042009 发表于 2025-11-26 16:42:36 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

引入说明

C++在设计上兼容了C语言的大部分语法特性,因此许多C语言代码可以在C++环境中直接编译运行。为了使用C++编译器进行编译,通常需要将源文件的后缀名改为.cpp。当Visual Studio等开发环境检测到.cpp扩展名时,会自动调用C++编译器进行处理。

#include <stdio.h>

int main()
{
	printf("hello world\n");
	return 0;
}

以下所示的C语言风格代码,在C++中同样可以成功编译和执行。不过值得注意的是,C++提供了一套更为现代化的输入输出机制,逐渐取代了传统的printf和scanf方式。

#include <iostream>

using namespace std;
int main()
{
	cout << "hello world" << endl;
	return 0;
}

接下来的内容将围绕C++的基础语法展开讲解,首先从命名空间开始。

命名空间(namespace)

1. 命名空间的作用与价值

在C和C++程序中,变量、函数以及类的数量往往非常庞大,这些标识符默认都位于全局作用域中,容易引发命名冲突问题。命名空间的引入正是为了解决这类名称污染和冲突现象。通过namespace关键字,可以将一组相关的标识符组织在一个独立的作用域内,实现局部化管理。

例如,在C语言环境下,以下情况极易导致编译错误:

#include <stdio.h>
#include <stdlib.h>
int rand = 10;
int main()
{
	printf("%d\n", rand);
	return 0;
}

该代码在编译时会报错,原因在于rand在标准库中已经被定义为一个函数名,若用户再次定义同名变量则会产生冲突。

2. 命名空间的定义方式

定义命名空间需使用namespace关键字,后接命名空间名称,再用一对花括号{}包裹其内部成员。命名空间中可包含变量、函数、类型等多种元素。

命名空间只能在全局范围内定义,支持嵌套结构。C++标准库中的所有组件均被封装在名为std(standard的缩写)的命名空间中。

本质上,命名空间创建了一个独立的作用域,与全局域相互隔离。不同命名空间下允许存在相同名称的变量或函数,从而避免了冲突。例如,下面的例子中rand就不会与标准库中的rand发生冲突。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;

namespace example
{
	int rand = 10;
}

int main()
{

	printf("%p\n", rand);//默认是访问的是全局的rand函数指针

	printf("%d\n", example::rand);//指定访问example命名空间里的rand
	return 0;
}

在介绍如何使用命名空间之前,先了解作用域限定符(::)。该操作符由两个冒号组成,用于指定访问某个特定命名空间中的成员。

命名空间的使用方法

命名空间支持嵌套定义,并可通过作用域解析符逐层访问其内部成员。

#include <stdio.h>
namespace EX
{
	namespace ex1
	{
		int rand = 10;
	}

	namespace ex2
	{
		int rand = 20;
	}
}
int main()
{
	printf("%d\n", EX::ex1::rand);
	printf("%d\n", EX::ex2::rand);

	return 0;
}

using关键字的应用

通过using namespace std;语句,可以将指定命名空间中的所有成员“展开”,使其在当前作用域中无需加前缀即可直接使用。这在日常练习中较为常见,尤其是在频繁使用cin、cout等标准库对象时。

#include <stdio.h>

namespace EX
{
	namespace ex1
	{
		int rand = 10;
	}
	
	namespace ex2
	{
		int rand = 20;
	}
}

using EX::ex1::rand;

int main()
{
	printf("%d\n", rand);
	return 0;
}

然而,在大型项目开发中,不推荐广泛使用using namespace std,因为它可能导致命名污染。此外,如果未正确展开所需命名空间,编译器将无法识别如rand等标识符,从而报错提示找不到声明。

C++输入与输出机制

<iostream> 是 Input Output Stream 的缩写,属于C++标准输入输出流库,其中定义了基本的输入输出对象。

  • std::cin 是 istream 类的一个实例,主要用于处理窄字符(char类型)的标准输入。
  • std::cout 是 ostream 类的对象,负责窄字符的标准输出。
  • std::endl 实际上是一个函数,插入输出流时相当于添加换行符并刷新缓冲区。

运算符 << 被重载为流插入操作符,而 >> 则作为流提取操作符使用。需要注意的是,这两个符号在C语言中原本用于位运算中的左移和右移操作。

C++的IO机制更加便捷,相比C语言中使用printf和scanf必须显式指定格式控制符,C++能够自动识别变量的数据类型(这一特性基于函数重载实现),更重要的是它能良好地支持自定义类型的输入输出操作。

由于IO流涉及类、对象、运算符重载、继承等一系列面向对象的核心概念,而这些内容尚未深入讲解,因此目前我们仅作初步认识。后续章节将专门详细剖析IO流库的设计与应用。

像cout、cin、endl等均属于C++标准库的一部分,它们统一位于std命名空间中,因此在使用时需配合命名空间访问方式(如std::cout)或通过using声明简化调用。

在一般练习场景中,使用using namespace std;是可接受的;但在实际工程项目中,建议避免整体展开标准命名空间,以防止潜在的命名冲突。

值得注意的是,即使没有显式包含<stdio.h>头文件,依然可以在程序中使用printf和scanf函数。这是因为某些编译器(如VS系列)在包含<iostream>时会间接引入C标准I/O函数。但其他编译器可能不具备此行为,可能会导致链接错误。

缺省参数(Default Parameters)

缺省参数是指在函数声明或定义时为其形参设定一个默认值。当调用该函数时,若未传入对应实参,则自动采用预设的默认值;否则使用调用者提供的实际参数。缺省参数可分为全缺省和半缺省两种形式(部分资料也称其为默认参数)。

全缺省指的是所有参数均设有默认值,而半缺省则是仅对部分参数设置默认值。根据C++语言规范,半缺省参数必须从右往左连续设置,不允许跳跃式地设定默认值。例如:

//正确形式(半缺省)
int ADD(int a,int b=10,int c=20)
//错误形式
int ADD(int a=10,int b,int c=20)

对于带有缺省参数的函数,在调用时也必须遵循从左到右依次传递实参的原则,不能跳过前面的参数只传后面的。

当函数的声明与定义分离时,缺省参数只能出现在函数声明中,不能同时在声明和定义中重复出现。这是C++的规定,旨在避免歧义和重复定义问题。

#include <iostream>

using namespace std;

void Func(int a = 0)
{
	cout << a << endl;
}

int main()
{
	Func();//不带参数,使用缺省值
	Func(10);//给出实参,则使用实参
	return 0;
}

函数重载(Function Overloading)

C++允许在同一作用域内存在多个同名函数,只要它们的参数列表不同即可构成重载。差异可以体现在参数个数、参数类型或参数顺序上。

//参数类型不同
int ADD(int x, int y)
{
	return x + y;
}

double ADD(float x, float y)
{
	return x + y;
}

//参数个数不同
void Func()
{
	cout << "Func()" << endl;
}

void Func(int a)
{
	cout << "Func(a)" << endl;
}

//参数顺序不同
void Func(int x, char y)
{
	//....
}

void Func(char y, int x)
{
	//....
}

需要特别注意:函数的返回类型不能作为重载的判断依据,因为在函数调用时,仅凭返回值无法确定应调用哪一个版本。

//void f()
//{
//
//}
//int f()
//{
//
//}

尽管函数重载提供了灵活性,但在实际使用中也可能遇到调用歧义的问题。

void Func()
{
	cout << "Func()" << endl;
}

void Func(int a)
{
	cout << "Func(a)" << endl;
}




int main()
{
	Func();
	
	return 0;
}

上述代码中,编译器无法明确选择调用哪个函数,从而产生二义性错误。解决此类问题的一种有效方式是将不同的函数置于不同的作用域(如命名空间)中,以消除冲突。

引用(Reference)

1. 引用的基本概念与定义

引用并不是创建一个新的变量,而是为已存在的变量提供一个别名。在编译过程中,编译器不会为引用分配独立的内存空间,它与其所引用的变量共享同一块内存区域。其语法格式如下:

类型& 引用别名 = 引用对象;

通过以下示例可以更清楚地理解引用的概念:

int main()
{
	int a = 0;
	int& b = a;
	int& c = a;//b和c是a的别名
	int& d = c;//d是c的别名,相当于是a的别名
	return 0;
}

在此例中,变量 a、b、c 和 d 实际上共享同一块内存空间。

引用具有以下几个重要特性:

  1. 引用在定义时必须进行初始化,不允许出现对空值的引用。
  2. 同一个变量可以拥有多个引用。
  3. 一旦某个引用被初始化后,它只能绑定到一个特定的实体,不能重新指向其他对象。
int main()
{
	int a = 10;
	int& ra = a;

	int c = 20;
	int b = c;//这里要分清楚,并非让b引用c,这是一个赋值,只是一个临时拷贝。

	return 0;
}

const 引用

在学习引用的过程中,const 引用是一个容易引起混淆的概念。为了准确理解,我们需要明确以下两点规则:

  1. 在发生类型转换时,系统会生成一个临时对象来保存转换后的值。根据 C++ 标准,这些临时对象具有“常量属性”,即它们是 const 类型的。
  2. 在引用过程中,目标对象的访问权限可以被缩小,但绝不能被放大。例如,可以用 const 引用去绑定非 const 对象,但反过来则不被允许。

下面通过代码示例进一步说明:

int main()
{
	int a = 10;
	int b = 20;
	int& f = a + b;//这样会报错,因为a+b返回一个值的时候会产生一个临时对象,这个临时对象是常量,如果按照前面这么写就将
	//权限放大了,变成了既可读,又可写。所以,我们要在前面加一个const修饰,const int& f=a+b; 

	return 0;
}
int main()
{
	const int a = 10;
	int& b = a;//同样是权限放大


	return 0;
}
int main()
{
	int a = 0;
	double& b = a;//类型转换,应该用const修饰
	return 0;
}

指针与引用的关系对比

  • 引用在底层实现上并不需要额外开辟内存空间,而指针作为独立变量,需要占用存储地址的空间。
  • 引用在定义时必须绑定到一个有效的对象,即必须初始化;而指针虽然建议初始化,但在语法上允许未初始化的存在。
  • 引用一经绑定便不可更改,始终指向初始对象;而指针可以在运行期间多次修改,指向不同的对象。
  • 引用可以直接操作其所代表的对象,无需特殊操作符;而指针必须通过解引用(*)才能访问目标数据。
  • 在使用 sizeof 运算符时,引用返回的是其所引用实体的实际大小;而指针无论指向何种类型,sizeof 的结果均为当前系统地址总线宽度对应的字节数(通常为 4 或 8 字节)。
二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:知识点 Hello World include RETURN Visual

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
jg-xs1
拉您进交流群
GMT+8, 2025-12-5 13:18