3.1 1-1c++概述
C++概述(了解)
c++语言在c语言的基础上添加了面向对象编程和泛型编程的支持。c++继承了c语言高效,简洁,快速和可移植的传统。
c++融合了3种不同的编程方式:
c语言代表的过程性语言.
c++在c语言基础上添加的类代表的面向对象语言.
c++模板支持的泛型编程。
C++初识
Hello World
#include; 预编译指令,引入头文件iostream.
using namespace std; 使用标准命名空间
cout << “hello world”<< endl; 和printf功能一样,输出字符串”hello wrold”
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;//标准命名空间
int main()
{
//cout是标准的输出流对象,打印字符串,
//endl是刷新缓冲区,并换行
cout << "hello world!" << endl;
system("pause");
return EXIT_SUCCESS;
}
面向对象三大特性
封装
把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
类将成员变量和成员函数封装在类的内部,根据需要设置访问权限,通过成员函数管理内部状态。
继承
继承所表达的是类之间相关的关系,这种关系使得对象可以继承另外一类对象的特征和能力。
继承的作用:避免公用代码的重复开发,减少代码和数据冗余。
多态
多态性可以简单地概括为“一个接口,多种方法”,字面意思为多种形态。程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。
命名空间(重点)
1.为什么有命名空间,是因为解决多人合作时取标识符是重命名的问题
2.什么是命名空间
namespace A{//A是空间的名字,
int a;
void func()
{
}
}
3.命名空间的注意
注意1:命名空间只能写在全局
注意2:命名空间可以嵌套命名空间
//命名空间可以嵌套命名空间
namespace Maker
{
int a;
namespace B
{
int b;
}
}
注意3:命名空间是开放,随时可以加入新成员,但是新成员只能在加入后使用
namespace Maker
{
int a;
namespace B
{
int b;
}
}
namespace Maker
{
int c;
}
注意4:匿名命名空间
//类似于static int d=50;
namespace
{
int d = 50;
}
注意5:命名空间可以取别名
void test01()
{
// 新名字 旧名字
namespace nameMaker = Maker;
cout << nameMaker::a << endl;
}
注意6:分文件编写代码时,如果.h中有两个命名空间,但是里面的成员函数或成员变量同名时,在.cpp中实现函数时,需要加上命名空间
test.h文件
#pragma once
#include<iostream>
using namespace std;
namespace myMaker1
{
void func();
}
namespace myMaker2
{
void func();
}
test.cpp文件
#include "test.h"
void myMaker1::func()//需要在函数名前面加入确定命名空间名字
{
cout << "func" << endl;
}
注意7: 命名空间可嵌套命名空间
namespace A{
int a = 10;
namespace B{
int a = 20;
}
}
void test(){
cout << "A::a : " << A::a << endl;
cout << "A::B::a : " << A::B::a << endl;
}
::作用域运算符
作用域运算符可以用来解决局部变量与全局变量的重名问题
//全局变量
int a = 10;
//1. 局部变量和全局变量同名
void test(){
int a = 20;
//打印局部变量a
cout << "局部变量a:" << a << endl;
//打印全局变量a
cout << "全局变量a:" << ::a << endl;
}
using声明和编译指令(重点)
using声明是让命名空间中某个标识符可以直接使用
namespace A
{
int a = 10;
int b = 20;
int c = 30;
}
void test01()
{
//using声明是让命名空间中某个标识符可以直接使用
using A::a;
cout <<a << endl;
//int a = 50;//注意:using声明了某个变量,在该作用域内不能定义同名的变量
}
using编译指令,让某个命名空间中的标识符都可以直接使用
namespace A
{
int a = 10;
int b = 20;
int c = 30;
}
void test02()
{
//using编译指令,让某个命名空间中的标识符都可以直接使用
using namespace A;
cout << a << endl;
cout << b << endl;
cout << c << endl;
int a = 100;//为什么不会冲突
//类似于命名空中的a是全局变量,这里的a的局部变量
cout << "a=" << a << endl;
}
struct类型加强
加强一:定义变量时不需要使用struct
加强二:结构体内可以写函数
//1. 结构体中即可以定义成员变量,也可以定义成员函数
struct Student{
string mName;
int mAge;
void setName(string name){ mName = name; }
void setAge(int age){ mAge = age; }
void showStudent(){
cout << "Name:" << mName << " Age:" << mAge << endl;
}
};
//2. c++中定义结构体变量不需要加struct关键字
void test01(){
Student student;
student.setName("John");
student.setAge(20);
student.showStudent();
}
更严格的类型转换(了解)
不能隐性的转换,必须显示的转换
typedef enum COLOR{ GREEN, RED, YELLOW } color;
int main(){
//以下c代码c编译器编译可通过,c++编译器无法编译通过。
char* p = malloc(64);
char* p = (char*)malloc(10);
return EXIT_SUCCESS;
}
三目运算符(了解)
c语言三目运算表达式返回值为数据值,为右值,不能赋值。
int a = 10;
int b = 20;
printf("ret:%d\n", a > b ? a : b);
//思考一个问题,(a > b ? a : b) 三目运算表达式返回的是什么?
//(a > b ? a : b) = 100;
//返回的是右值
c++语言三目运算表达式返回值为变量本身(引用),为左值,可以赋值。
int a = 10;
int b = 20;
printf("ret:%d\n", a > b ? a : b);
//思考一个问题,(a > b ? a : b) 三目运算表达式返回的是什么?
cout << "b:" << b << endl;
//返回的是左值,变量的引用
(a > b ? a : b) = 100;//返回的是左值,变量的引用
cout << "b:" << b << endl;
[左值和右值概念]
在c++中可以放在赋值操作符(=)左边的是左值,可以放到赋值操作符右面的是右值。
有些变量即可以当左值,也可以当右值。
左值为Lvalue,L代表Location,表示内存可以寻址,可以赋值。
右值为Rvalue,R代表Read,就是可以知道它的值。
比如:int temp = 10; temp在内存中有地址,10没有,但是可以Read到它的值。
C/C++的const(重点)
1.C语言的const修饰的变量都有空间
2.C语言的const修饰的全局变量具有外部链接属性(使用extern来引用其他文件的常量)
3.C++语言的const修饰的变量有时有空间,有时没有空间(发生常量折叠,且没有对变量进行取址操作)
const int aa = 10;//没有内存
void test01()
{
//发生了常量折叠
cout << "aa=" << aa << endl;//在编译阶段,编译器:cout<<"aa="<<10<<endl;
//禁止优化volatile
//volatile const int bb = 20;//栈区
const int bb = 20;
int *p = (int*)&bb;//进行了取址操作,所以有空间
*p = 200;
cout << "bb=" << bb << endl;//cout << "bb=" << 20 << endl;
cout << "*p=" << *p << endl;
cout << "a的地址=" << (int)&bb << endl;
cout << "p指向的地址" << (int)p << endl;
}
4.C++语言中const修饰的全局变量具有内部链接属性(只能在本文件中使用)
extern const int c = 300;//加上extern就变为外部链接属性(可以其他文件使用)
5.C++编译器不能优化的情况
1.不能优化自定义数据类型
2.如果用变量给const修饰的局部变量赋值,那么编译器就不能优化
3.编译器是在编译阶段来优化数据
C/C++中const异同总结
c语言全局const会被存储到只读数据段。c++中全局const当声明extern或者对变量取地址时,编译器会分配存储地址,变量存储在只读数据段。两个都受到了只读数据段的保护,不可修改。
const int constA = 10;
int main(){
int* p = (int*)&constA;
*p = 200;
}
以上代码在c/c++中编译通过,在运行期,修改constA的值时,发生写入错误。原因是修改只读数据段的数据。
c语言中局部const存储在堆栈区,只是不能通过变量直接修改const只读变量的值,但是可以跳过编译器的检查,通过指针间接修改const值。
const int constA = 10;
int* p = (int*)&constA;
*p = 300;
printf("constA:%d\n",constA);
printf("*p:%d\n", *p);
运行结果:
c语言中,通过指针间接赋值修改了constA的值。
c++中对于局部的const变量要区别对待:
- 对于基础数据类型,也就是const int a = 10这种,编译器会进行优化,将值替换到访问的位置。
const int constA = 10;
int* p = (int*)&constA;
*p = 300;
cout << "constA:" << constA << endl;
cout << "*p:" << *p << endl;
运行结果:
- 对于基础数据类型,如果用一个变量初始化const变量,如果const int a = b,那么也是会给a分配内存。
int b = 10;
const int constA = b;
int* p = (int*)&constA;
*p = 300;
cout << "constA:" << constA << endl;
cout << "*p:" << *p << endl;
运行结果:
constA 分配了内存,所以我们可以修改constA内存中的值。
3. 对于自定数据类型,比如类对象,那么也会分配内存。
const Person person; //未初始化age
//person.age = 50; //不可修改
Person* pPerson = (Person*)&person;
//指针间接修改
pPerson->age = 100;
cout << "pPerson->age:" << pPerson->age << endl;
pPerson->age = 200;
cout << "pPerson->age:" << pPerson->age << endl;
运行结果:
为person分配了内存,所以我们可以通过指针的间接赋值修改person对象。
尽量用const替代define
1.define没有数据类型,const修饰的变量有数据类型,可以进行数据类型检查
#define MA 128
const short ma = 128;
void func(short a)
{
cout << "func(short a)" << endl;
}
void func(int a)
{
cout << "func(int a)" << endl;
}
int main()
{
func(ma);
system("pause");
return EXIT_SUCCESS;
}
2.const修饰的变量有作用域,define不重视作用域,不能限定常量的使用范围