并非从0开始的c++ day12

本文介绍了C++语言的基础知识,包括C++的面向对象特性——封装、继承和多态,以及命名空间的使用和作用域运算符的概念。此外,还讨论了using声明和编译指令,struct类型的增强功能,以及C++中const变量的处理和编译器优化策略。
摘要由CSDN通过智能技术生成

C++概述

C++语言在c语言的基础上添加了面向对象编程和泛型编程的支持。C++继承了c语言高效,简洁,快速和可移植的传统
C++融合了3种不同的编程方式:

  • c语言代表的过程性语言
  • c++在c语言基础上添加的类代表的面向对象语言
  • C++模板支持的泛型编程

第一个C++程序

经典hello world,对比c语言来学习


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;//标准命名空间

int main(int argc, char** argv)
{
	cout << "hello world" << endl;
	system("pause");
	return 0;
}

iostream是c++的头文件
C++的头文件有3个部分组成,1部分是c原来的头文件,有.h结尾,一部分是c++新加的头文件,如这里的iostream没有.h结尾,还有一部分为c++重写了c原来的头文件,这些头文件与c原来的头文件名字一致,但没有.h,如math

using namespace std;为标准命名空间

cout << “hello world” << endl;为标准输出流对象
用于打印字符串
cout可以看做char out字符输出 ,endl可以看做end line 用作刷新缓冲区并换行

面向对象三大特性

封装

把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏
类将成员变量和成员函数封装在类的内部,根据需要设置访问权限,通过成员函数管理内部状态

继承

继承所表达的是类之间相关的关系,这种关系使得对象可以继承另外一类独享的特征和能力
继承的作用:避免公用代码的重复开发,减少代码和数据冗余

多态

多态性可以简单地概括为“一个接口,多种方法”,字面意思为多种形态。程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念

名字控制

C++命名空间

命名空间为了解决多人合作时取标识符是重命名的问题

namespace A {//命名空间 A为空间名字
	int a;
	void func() {

	}
}

命名空间的注意事项

  1. 命名空间只能写在全局
  2. 命名空间可以嵌套命名空间
//命名空间可以嵌套命名空间
namespace Maker
{
	int a;
	namespace B
	{
		int b;
	}
}
  1. 命名空间是开放的,随时可用加入新成员,但是新成员只能在加入后使用
void test()
{
	cout << Maker::c << endl;
}
namespace Maker
{
	int c;
}

如果代码如上编写,在编译时就会报错

  1. 匿名命名空间
namespace
{
	int d = 50;
}

只有在同一个文件下,才能输出使用
类似于static int d = 50;

  1. 命名空间可以写别名
void test01()
{
	//        新名字       旧名字
	namespace nameMaker = Maker;
	cout << nameMaker::a << endl;
}

上述代码能正常访问

  1. 分文件编写代码时,如果.h中有两个命名空间,当时里面的成员函数或成员变量同名时,在.cpp中实现函数时,需要加上命名空间
    如在test.cpp文件中
#include"test.h"
void myMaker1::func()
{
	cout << "func" << endl;
}

作用域运算符

通常情况下,如果有两个同名变量,一个是全局变量,另一个是局部变量,那么局部变量在其作用域内具有较高的优先权,它将屏蔽全局变量

int mya = 10;

int main(int argc, char** argv)
{
	int mya = 20;
	cout << "mya= " << mya << endl;
	system("pause");
	return 0;
}

两个同名变量在输出时,会根据就近原则,如上例子会输出第二个变量
想要输出全局变量,就要用到作用域运算符

cout << "::mya=" << ::mya << endl;

同理,可以用作用域运算符输出自定义命名空间里的成员变量

cout << Maker::c << endl;

遇到嵌套的命名空间需要一层层往下访问

cout << Maker::B::b << endl;

using

using声明

using声明可使得指定的标识符可用

namespace A
{
	int a = 10;
	int b = 20;
	int c = 30;
}

void test01() 
{
	using A::a;
	cout << a << endl;
}

using声明是让命名空间中某个标识符可以直接使用
需要注意的是:
using声明了某个变量,在该作用域内不能定义同名的变量
放上面的例子则是,不能再test01中定义一个a

using编译

using编译指令,让某个命名空间中的表示符都可以直接使用

void test02()
{

	using namespace A;
	cout << a << endl;
	cout << b << endl;
	cout << c << endl;
}

需要注意的是,这里就没有二义性的问题,可以在其中声明同名变量
在上面的例子则是可以声明一个a ,若输出该变量,则根据就近原则输出

这里不会报错的原因,类似于命名空间中的a是全局变量,这里的a是局部变量,是因为作用域不同

struct类型加强

  • c中定义结构体变量需要加上struct关键字,c++不需要
struct Maker
{
	char name[64];
	int age;
};

void test01()
{
	Maker a;
}

struct类型就是自定义是数据类型,和int相同,在未生成对应变量的时候,不会占据内存空间

  • c中的结构体只能定义成员变量,不能定义成员函数。c++即可定义成员变量,也可以定义成员函数
struct Maker2
{
	int a;
	void func()//结构体内部可以写函数
	{
		cout << "func" << endl;
	}
};

void test02()
{
	Maker2 a2;
	a2.func();
}

更加严格的类型转换检查

//这种方式不能进行隐式转换,必须显示转换
char* p = (char*)malloc(64);

若不加上(char*),在c中不会报错,但是在c++中会报错,因为类型转换的检查更加严格了

三目运算符

三目运算符也即 a>b ? a : b,形式的为三目运算符
这个表达式返回的是右值,是数值,不能通过= 来直接修改他的值

若想修改他的值,需要用指针和取地址来修改对应的值

void test()
{
	int a = 10;
	int b = 20;
	printf("%d\n", a > b ? a : b);
	*(a > b ? &a : &b) = 100;
	printf("b = %d\n",  b);
}

若在c++里想要做到这个效果,因为c++返回的是左值,是空间,所以可以直接赋值

void test01()
{
	int a = 10;
	int b = 20;
	(a > b ? a : b) = 100;
	cout << "a=" << a << endl;
	cout << "b=" << b << endl;
}

const 概述

const用来限制一个变量不允许改变,它将一个对象转换成一个常量

c语言的全局const变量

const int a = 10;//常量区,一旦初始化,不能修改


int main(int argc, char** argv)
{
	int* p = (int*)&a;
	//*p = 100;
	//printf("%d\n", a);

	system("pause");
	return 0;
}

全局的const不能直接修改,编译器会直接报错,也不能间接修改,虽然语法没报错,但是编译阶段会报内存错误
c语言的const修饰的变量都有空间

c语言的局部const变量

const int b = 20;
//b = 200;

直接修改也会直接语法报错

int* p = (int*)&b;
*p = 200;
printf("%d\n", b);

但是间接修改不会报错

c语言使用别的文件的全局const修饰的变量

使用别的文件的全局const修饰的变量需要声明

extern const int c;
printf("c = %d\n", c);

c语言的const修饰的全局变量具有外部链接属性

C++的全局const变量

const int aa = 10;//没有内存

void test01()
{
	cout << "aa= " << aa << endl;
}

在编译阶段:编译器:cout << “aa=” << 10 <<endl;
这样既可以节省空间,不需要存aa这个变量,还可以节省时间,毕竟输出变量的时间比输出常量的时间长

C++的局部const变量

const int bb = 20;//栈区
int* p = (int*)&bb;
*p = 200;
cout << "bb = " << bb << endl;
cout << "*p = " << *p << endl;

第一个输出语句输出的是20,第二个输出语句输出200,这是因为在输出第一个语句时,编译器自动将bb替换为了20,而没有管bb地址包含的值,而对应的值其实已经修改了

直接输出他们的地址,会发现他们的地址其实是一样的,更加验证了上述的观点

若声明时,写的是下述代码,则可以通过间接修改,修改他的值,但是输出地址时,输出的是一个bool值,一般是1

volatile const int bb = 20;

volatile代表禁止优化,可以防止编译器作出上述优化行为
上述编译器做出的优化,用专业术语描述为:常量折叠
发生常量折叠,且没有对变量进行取值操作时,C++语言的const修饰的变量没有空间,其他情况下有空间

c++语言中使用其他文件中的const修饰的全局变量

extern const int c;
cout << "c = " << c << endl;

会编译失败,可知C++语言中const修饰的全局变量具有内部链接属性
只能在本文件内部访问

不过若在原文件的const声明前,加上extern关键字,则可以使其具有外部链接属性

C++编译器不能优化数据的情况

若局部const变量初始化时,赋值的为一个变量,那么编译器不会优化

void test()
{
	int a = 10;
	const int b = a;
	int* p = (int*)&b;
	*p = 100;
	cout << " b =" << b << endl;
	cout << "*p = " << *p << endl;
}

自定义数据类型,编译器不会优化

struct Maker
{
	Maker()//构造函数
	{
		a = 100;
	}
	int a;
};

void test02()
{
	//数据类型定义变量
	//类实例化对象
	const Maker ma;
	cout << ma.a << endl;
	Maker* p = (Maker*)&ma;
	p->a = 200;
	cout << ma.a << endl;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值