c++_note_1_c++对c的扩展


#1. c++对c的扩展

变量定义方面:命名空间,不能重复定义全局变量,定义位置更灵活。

数据类型方面:struct,register,const,bool,并且变量和函数必须有类型。

另外还有三目运算符、等号等操作符的优化,以及函数扩展。

1.1 命名空间

引入namespace,更好地控制标识符的作用域,避免冲突。
c语言只有一个全局作用域,也叫默认命名空间,被所有全局标识符共享,可能发生冲突。
c++将全局作用域分成不同部分,不同namespace的标识符可以重名并不冲突。
命名空间可以相互嵌套。

定义

namespace ns1{
    int foobar = 1;
}

使用namespace:using namespace ns1;
使用嵌套的命名空间:using namespace ns1::ns2
使用namespace中的变量:using ns1::foobar;
使用默认namespace中的变量:::foobar,或者直接使用foobar::cout-->cout
若没有using namespace std,需要这样写:std::cout,因为iostream没有引入std。

C++中可以同时using 两个命名空间,但前提是这两个空间中没有相同的变量或函数.

c++为了与c区分,规定头文件不使用后缀.h
iostream.h在include中是另一个文件,速度慢,c++标准已经不支持。

##1.2 变量定义位置
c++变量可以在需要时定义

1.3 register

register关键字优化,
c中,register修饰的变量不能取地址,c++可以。
取register变量地址时,register声明无效。
并且不使用register关键字也可以优化,比如循环中的index变量。

1.4 全局变量的检测

c中,定义重名的全局变量是合法的,它们会被链接到全局数据区的同一地址空间上。
c++则不允许重复定义全局变量。

int a;
int a = 1;
int main(){..}

这段代码,c不会报错,c++会报错。

1.5 struct

c中,struct并不被编译器当作类型。
c++中,struct是新类型的定义声明。并且能用访问修饰符。

struct Person{
public:
	int age;
};
int main()
{
	Person p;
	return 0;
}

1.6 变量和函数必须有类型

类型检查不严格是c的缺陷。

func(i){
	printf("1\n");
}
int main()
{
	func(1,2,3);
	return 0;
}

这段代码在c中不会报错并且会执行。
在c中,int f()接收任意参数,int f(void)无参;而c++中它们都是无参。

1.7 bool类型

理论上占1字节,多个bool定义在一起可能各占1bit,这取决于编译器的实现。
编译器 用0和1表示,输出也为1或0。
c中需要#include<stdbool.h>
或者
typedef enum{false = 0, true = 1} bool;
或者
typedef int bool;
#define true 1
#define false 0
或者
#define bool int
#define true 1
#define false 0

1.8 三目运算符

( a < b ? a : b ) = 3;
在c中,表达式不能做左值。
在c中,表达式的运算结果放在寄存器中。且表达式的返回值是一个具体的数
在c++中表达式返回的是变量自身,或者说返回一个内存空间(or内存的首地址or指针),c++编译器帮程序员完成了取地址的工作。

c中可以这样实现:

int c = 1;
int d = 2;
*( c < d ? &c : &d ) = 3;

1.9 关于const

const意味着只读
复习
int * const a; //指针常量
const int * a; //int常量

typedef struct {
	int age;
} Person;

void f1(const Person * p){
	//p->age = 1;
	p = NULL;
}
void f2(Person * const p){
	p->age = 1;
	//p = NULL;
}

真正的常量

c中,const变量可以通过指针更改。

int main()
{
	const int a = 1;
	int *p = NULL;
	p = (int*)&a;
	printf("&a:%08X\n",&a);
	cout<<"p :"<<p<<endl;
 
	*p = 2;
	printf("a:%d\n",a);
	*(int*)&a = 3;
	printf("a:%d\n",a);

	//cout<<"*p :"<<*p<<endl;
	return 0;
}

但在c++中,这段代码无效。因为c++不再给const变量单独分配内存,而是放在符号表(key:value)中。
当用指针取地址时,会单独分配内存。cout<<"*p :"<<*p<<endl会显示这块内存。
所以c++中的const变量才是真正的常量。

总结一下就是:
c中,const变量分配存储空间;
c++中,以下情况会分配空间:

  • 使用&取const变量地址;
  • const变量是全局变量,并被其它文件使用。

并且,c++的const变量分配内存是在编译期间。

int main()
{
	int a;
	const int b = 1;
	int c;
	cout<<&a<<endl;
	cout<<&b<<endl;
	cout<<&c<<endl;

	cin.get();
	return 0;
}

输出
0x66ff34
0x66ff30
0x66ff2c
可以证明分配顺序并不是a、c、b.

对比宏

const其实是c++替换c的#define的一种方法。

int a = 1;
int b = 2;
int c[a+b];
/*
linux内核的gcc支持;c/c++编译器不支持。
下面这样写则是支持的,由此代替了宏定义。
*/

const int a = 1;
const int b = 2;
int c[a+b];

const和宏定义都是编译期处理的。
它们的不同之处在于:

  • const由编译器处理,提供类型检查和作用域检查;
  • 宏定义由预处理器处理,是文本替换。
void f1()
{
	#define a 1
	const int b = 2;
	#undef a
}
void f2()
{
	printf("%d\n",a);
	//printf("%d\n",b);
}

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

常量成员函数

常量成员函数,不能通过this指针修改无mutable修饰的成员变量 。 编译器将对这些const成员函数进行检查, 如果确实没有修改对象值的行为,则检验通过。

1.10 函数扩展

c++对c的函数扩展有:
内联,默认参数,占位参数,函数重载

inline

常引用可以替代宏常数,而内联函数可以替代宏代码。

inline int func(){...}

inline关键字必须写在函数定义的地方,而不是声明的地方。

内联函数在最终生成的代码中是没有定义的,直接将函数体插入到调用处,也就没有了压栈、跳转、返回的开销。

宏代码是预处理器处理的,无编译过程;内联函数是由编译器处理的。

一般很短的代码才内联,如简单输出、三目运算这些可以define的操作。

没有inline关键字的简短函数也可能内联编译。

编译器接收inline请求的条件:

  • 不能有循环,不能有过多条件判断。
  • 不能有取址操作

也就是说编译器可以拒绝内联编译请求。

默认参数

int func(int arg = 1){...};

默认参数应在非默认参数的右边
传参时也可以传入实参改变默认参数
func(2)

占位参数

int func(int x , int){}
调用时必须传入占位参数。

占位参数没有形参名,函数体内无法使用。它的意义在于兼容C语言中的不规范写法,以及日后扩展。

一般结合默认参数
int func(int x , int=1){}

函数重载

相同函数名,不同参数,也就是说,函数重载由函数名和参数决定,而返回值及类型不是重载的因素。

void func(int a, int b, int c = 0){}
void func(int a, int b){}
func(1,2)
上面这段代码遇到默认参数,有二义性,编译不通过。

函数指针

#include <iostream>
using namespace std;

void func(char *s){
	cout<<s<<endl;
	return;
}
void func(char a,char b){
	cout<<"two chars"<<endl;
	//cout<<a<<endl;
	return;
} 

//声明一个函数类型 
typedef void (myFuncType)(char *s);

//声明一个函数指针类型 
typedef void (*myPFuncType)(char *); 
typedef void (*myPFuncType2)(char,char); 
 
int main(int argc, char *argv[])
{
	myFuncType funcType; 
	myPFuncType pFuncType = NULL;
	myPFuncType2 pFuncType2 = NULL;
	
	pFuncType = func;
	pFuncType2 = func;
	pFuncType("pfunctype");
	pFuncType2('a','b');
	
	//定义一个函数指针变量 
	void (*pFunc)(char *s);
	pFunc = func;
	(*pFunc)("pfunc");
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值