day1
03课:用面向对象的方法求解圆的面积,类和对象的关系思考
#include "iostream"
using namespace std;
/*void main_()//面向过程求法
{
double r = 0;
double s = 0;
cout << "plases input the circle radius:";
//cin标准输入 代表键盘
cin >> r;
cout << "r的值是:" << r << endl;
s = 3.14 * r * r;
cout << "圆的面积是s:" << s << endl;
}*/
//用面向过程的方法
struct Circle
{
double m_s; //圆的面积
double m_r; //圆的半径
};
class mycircle
{
public:
double m_s; //圆的面积 属性 成员变量
double m_r; //圆的半径
void setR(double r)//成员函数
{
m_r = r;
}
double getR()
{
return m_r;
}
double getS()
{
m_s = 31.4 * m_r * m_r;
return m_s;
}
};
//用面向对象的方法
//1 类的抽象 成员变量和成员函数
//2 实例化
//3求面积
//面向过程加工的是一个一个的函数
//面向对象加工的是一个一个的类
//4main集成测试
//思考1:类的调用 执行过程分析==>类代码不是一步一步指向
//类是一个数据类型,(固定大小内存块的别名);定义一个类,是一个抽象的概念,不会给你分配内存
//用数据类型定义变量的时候,才会分配内存
void main()
{
mycircle c1, c2, c3; //用类 定义 变量 对象
double r1,r2,r3;
cout << "please input c1 circle radius";
cin >> r1;
//给c1圆形的属性赋值
c1.setR(r1);
cout << "c1 of area is:" << c1.getS() << endl;
cout << "please input c2 circle radius";
cin >> r2;
//给c1圆形的属性赋值
c2.setR(r2);
cout << "c2 of area is:" << c2.getS() << endl;
}
04课:类中不写成员函数易犯的错误模型
#include <iostream>
using namespace std;
class circle
{
public:
double r;
double pi=3.1415926;
double area=pi*r*r;
};
//2010编译不通过,但是2013的编译器可以,但输出结果为乱码
int main()
{
circle pi;
cout <<"请输入area"<<enl;
cin >>pi.r;
cout <<pi.area<<endl; //乱码
return 0;
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bV1GNMFC-1602678752458)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1602500993898.png)]
-
初始化的时候已执行,当时r是一个随机值;
-
结果:造成area变量的值是一个乱码
当c1
05课:易犯错误模型-为什么需要成员函数(补充资料)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EUhicY36-1602678752461)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1602505953810.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VpB5OKNE-1602678752462)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1602506538758.png)]
09 namespace和iostream
#include "iostream"
using namespace std;
//1文件中iosstream没有引入标准的std;需要我们程序员自己手工的写
//2如果不写using namespace std;需要我们引入std
void main()
{
cout <<"namespace tset"<<endl;
std::cout<<"namespace test"<<std::endl
}
//3定义命名空间
namespace namespaceA
{
int a=10;
}
namespace namespaceB
{
int a=20;
namespace namespaceC
{
struct Teacher
{
char name[32];
int age;
}
}
}
//使用命名空间
void main()
{
using namespace namespaceA;
using namespace namespaceB;
cout<<namespaceA::a<<endl;
cout<<namespaceB::a<<endl;
//显示的,写全
{
//namespaceB::namespaceC::Teacher t1;
//t1.age=33;
}
//
using namespaceB::namespaceC::Teacher;
Teacher t2;
t1.age=36;
}
结论:
- 当使用的时候,该头文件没有定义全局变量命名空间,必须使用namespace std;这样才能正确使用cout。若不引入using namespace std ,需要这样做。std::sout。
- C++标准为零和c区分开来,也为了正确使用命名空间,规定头文件不适用后缀".h"。
- C++命名空间的定义:namespace name{。。。}
- using namespace NameSpaceA;
- namespcae定义可以嵌套
10课:实用性加强_register增强,检测增强(1)
register关键字增强
//registeer关键字 请求编译器让变量a直接存放在寄存器中,速度快
//在c语言中 register 修饰的变量 不能取地址,但是在c++里面做了内容
//1
register 关键字的变化
register关键字请求“编译器”将局部变量存储在寄存器中
c语言中无法取得register变量地址
在c++中依然支持register关键字
c++编译器有自己的优化方式,不使用register也可能做优化
c++中可以取得register变量的的地址
//2
c++编译器发现程序中需要取register变量的地址时,register对变量的申明变无效。
//3
早起c语言编译器不会对代码进行优化,因此register变量是一个很好的补充。
int mian()
{
register int a=0;
printf("&a=%x\n",&a);
return 0;
}
变量检测的增强
/*在c语言中,重复定义类多个同名的全局变量是合法的
在c++中,不允许定义多个同名变量
C语言中多个同名变量最终会被链接到全局数据区的同一个地址空间上
int g_var;
int g_var=1;
c++直接拒绝这种二义性的做法
*/
11课:struct关键字类型增强
/*C语言的struct定义了一组变量的集合,c编译器并不认为这是一种新的类型
c++中的struct是一个新类型的定义声明*/
(上述意思理解:c’语言中使用struct定义一个类型结构体,在主函数中声明一个变量是该类型的结构体,需要使用struct,而c++不需要使用struct)
12课:c++类型检测加强
c++中所有的变量和函数都必须有类型
/*c语言中的默认类型在c++中是不合法的
函数f的返回值是什么类型,参数又是什么类型?
函数g可以接受多少个参数?
跟换成.cpp试试。
f(i)
{
printf("i=%d\n",i);
}
g()
{
return 5;
}
int main()
{
f(10);
printf("g()=%fd\n",g(1,2,3,4,5));
getchar();
return 0;
}
13课:新增Bool类型关键字
/*c++中的布尔类型
c++在c语言的基本类型系统之上增加类bool
c++中的bool可取得值只有true和false
理论上bool只占一个字节
如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现
true代表真值,编译器内部用1来表示
false代表非真值,编译器内部用0来表示
bool类型只有true和false两个值
c++编译器会在赋值时将非0值转换成true,0值转化成false
15课:c++中的三目运算符
三目运算符在c和c++编译器的表现
//在c语言中 表达式的结果 存放在寄存器中
//1
//在c语言中,表达式的返回值 是一个数
//在c++中,表达式返回的是变量的本身
//2 如何做到(要使得其能够作为左值,则其必需是一个变量)
//让表达式返回一个内存空间 内存的首地址 指针
int mian()
{
int a=10;
int b=20;
//返回一个最小数 并且给最小数赋值成3
//三木运算符是一个表达式,表达式不可能做左值
(a<b?a:b)=30; //c语言这么做可以达到c++此行代码一样的效果 *(a<b?&a:&b)=30;
printf("a=%d,b=%d\n",a,b);
return 0;
}
结论:
-
c语言返回变量的值,c++是返回变量本身
c语言中的三木运算符返回的是变量值,不能作为左值使用
c++中的三目运算符可以直接返回变量本身,因此可以出现在程序的任何地方
-
注意
16课:const基础和const符号表机制探究。
const基础用法
int main()
{
const int a;
int const b;
const int *c;//不能通过指针来修改指针指向的变量
int* const d;//不能修改指针的指向(即不可修改指针变量的内存中的数据)
const int* const e;
return 0;
}
int func1(const)
//初级理解:const是定义敞亮==>const意味着只读
//含义:
//第一个第二个意思一样 代表一个常整形数
//第三个 c是一个指向常整形数的指针(所指向的内存数据不能被修改,但是本身可以修改)
//第四个 d常指针(指针不能被修改,但是它所指向内存空间可以被修改)
//第五个 e指向一个常整形的常指针(指针和它所指向的内存空间,均不能被修改)
//const的好处
//合理利用const
//指针函数参数,可以有效的提高代码可读性,减少bug
//清楚的分清参数的输入和输出的特性
//c语言中const不够完善,如下列代码在c编译器中执行结果为20
void main()
{
//好像a是一个常数 其实不然
const int a=10;
//a=11; 如果加入此段,编译器会报错说a为不可修改左值
int* p=NULL;
p=(int*)&a;
*p=20; //间接取值,
printf("a:%d\n",a);
}
//c++中const是真正的const!(c++对const做了更特殊的处理)
结论:(此结论未完整,17课结论更为完整)
c语言中的const变量
c语言中的const变量是只读变量,有自己的存储空间
c++中的const变量
可能分配存储空间,也可能不分配内存空间
当const常量为全局,并且需要在其它文件中使用(分配)
当使用&操作符取const常量的地址(分配)
17课:const和#define的对比
//const分配内存的时机 编译器编译期间
const 是替换#define的手段
-
const和#define的相同之处
//练习 解释为什么 //它们都是在编译阶段处理的 int mian() { const int a=1; const int b=2; int array[a+b]={0};//如果前面的a和b在定义时未声明const,则在c或c++编译器中改行代码都会报错,因为变量不能作为数组在定义时的下标(c和c++编译器不支持该语法现象) //但是在Linux内核里面却成立,原因是Linux内核的gcc编译器支持 int i=0; for(i=0;i<a+b;i++) { printf("arry[%d]=%d\n",i,arry[i]); } printf("Please enter to continue..."); getchar(); return 0; }
-
const和#define的区别
对比加深
c++中的const常量类似于宏定义
const int c=5<=>#define c 5
c++中的const常量与宏定义不同
const常量是由编译器处理的,提供类型检查和作用域检查
宏定义由预处理器处理,单纯的文本替换
//练习 void fun1() { #define a 10 const int b=20; //#undef a # undef//此句为卸载a相关的宏定义,若不加a也行(#undef)为卸载所有宏定义 } void fun2() { printf("a=%d\n",a); //printf("b=%d\n",b); } int main(int argc,char*argv[],char**env) { fun1(); fun2(); return 0; }
结论:
c语言中的const变量
c语言中的const变量是只读变量,有自己的存储空间
c++中的const变量
可能分配存储空间,也可能不分配存储空间
当const常量为全局,并且需要在其它文件中使用,会分配存储空间
当使用&操作符,取const常量的地址时,会分配存储空间
当const int &a=10;const修饰引用时,也会分配内存空间
18课:引用的基础知识(定义和函数参数)
-
引用(普通引用)
变量名回顾
变量名实质是上是一段连续存储空间的别名,是一个标号
程序中通过变量申请并命名内存空间
通过变量的名字可以使用存储空间
问题1:对一段连续的内存空间只能取一个别名吗?可以
-
引用概念
a)在c++中新增加了引用的概念
b)引用可以看作一个定义变量的别名
c)引用的语法:Type& name = var;
d)引用作函数哪?(引用作为函数参数声明是不进行初始化)
void mian()
{
int a=10;//c编译器分配4个字节内存。。。内存空间的别名
int &b=a; //b就是a的别名
a=11;//直接赋值
{
int *p=&a;
*P=12;
printf("a %d\n",a);
}
b=14;
printf("a:%d b:%d",a,b);
}
-
引用是c++的概念
属于c++编译器对c的扩展
//问题:c中可以编译通过吗? int main() { //普通引用需要初始化 int a=0; int &b=a; //int* const b=&a b=11; //*b=11 return 0; } //结论:请不要用c语言的语法考虑b=11
-
引用做函数参数
普通引用在声明是必须用其它的变量进行初始化
引用作为函数参数声明时不进行初始化
void fun(int &a,int &b)
{
int c=0;
c=a;
a=b;
b=c;
}
void main()
{
int x,y;
x=10;
y=20;
fun(x,y);
printf("x:%d,y:%d\n",x,y);
}
19课:复杂数据类型引用做函数参数
struct Teacher
{
char name[64];
int age;
};
void printfT(Teacher *pT)
{
cout<<pT->age<<endl;
}
//PT为别名,相当于修改了t1
void printfT2(Teacher &pT)
{
pT.age=33;
//cout<<pT.agae<<endl;
}
//pT和t1是两个不同的变量,相当于修改了
void printfT3(Teacher pT)
{
cout<<pT.age<<endl;
pT.age=45;//只会修改pT变量,不会修改t1变量
}
void main()
{
Teacher t1;
t1.age=35;
printfT(&t1);
printfT2(t1); //pT是t1的别名
printf("t1.age:%d\n",t1.age);//35
printfT3(t1); //pT是形参,t1copy一份数据给pT //-->pT=t1
cout<<"hello..."<<endl;
}
20课:引用的本质剖析
1)引用作为其它变量的别名而存在,因此在一些场合可以代替指针
2)引用相对于指针有更好的实用性
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-D6qRQ1wR-1602678752464)(C:\Users\Administrator\Desktop\图片\QQ截图20201014181540.png)]
思考1.c++编译器背后做了什么工作?
int mian()
{
int a=10;
int &b=a;
//b是a的别名,请问c++编译器做了什么工作?
b=11;
cout<<"b-->"<<a<<endl;
printf("a:%d\n",a);
printf("&a:%d\n",&a);
printf("&b:%d\n",&b); //请思考:对于同一内存空间可以取好几个名字吗?
return 0;
}
思考2:普通引用有自己的空间吗?
struct Teacher
{
int &a;
int &b;
}
int mian()
{
printf("sizeof(Teacher)%d\n",sizeof(Teacher));
return 0;
}
引用是有一个地址,但引用是常量。
char* const p
- 引用的本质
1)引用在c++中的内容实现是一个常指针
Type&name<–>Type* const name
2)c++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占的空间大小与指针相同。
3)从使用的角度,引用会让人误会只是一个别名,没有自己的内存空间,这是c++为了实用性而做出的细节隐藏。
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IJVFEf6q-1602678752465)(C:\Users\Administrator\Desktop\图片\QQ截图20201014190840.png)]
引用结论(此结论笔记主认为有错,个人认为应该参考汇编语言里的标号来理解,而不是这里所谓的常量指针)
1)引用在实现上,只不过是把:间接赋值成立的三个条件的后两步和二为一
//当实参传给形参的时候,只不过是c++编译器帮我们程序员手工取了一个实参地址,传给了形参引用(常量指针)
2)当我们使用引用语法时,不需要去关心编译器怎么做,当我们分析
21课:函数返回值是引用(当左值右值)
c++引用使用时的难点:
当函数返回值为引用时
若返回栈变量
不能作为左值使用
若返回静态变量或全局变量
可以成为其它引用的初始值
即可作为右值使用,也可以作为左值使用
c++链式编程中,经常用到引用,运算符重载专题
返回值是基础类型,当引用
int getAA1()
{
int a;
a=10;
return a;
}
//基础类型a返回时,也会有一个副本
int& getAA2()
{
int a;
a=10;
return a;
}
int* getAA3()
{
int a;
a=10;
return &a;
}
void main()
{
int a1=0;
int a2=0;
a1=getAA1();
a2=getAA2();//10
int &a3=getAA2();
printf("a1:%d \n",a1);
printf("a2:%d \n",a2);
printf("a3:%d \n",a3);
cout<<"hello..."<<endl;
}
返回值是static变量,变量是一个状态变量
//static修饰变量的时候,变量是一个状态变量
int j()
{
static int a=10;
a++;
printf("a:%d\n",a);
return a;
}
静态变量或全局变量
可以成为其它引用的初始值
即可作为右值使用,也可以作为左值使用
c++链式编程中,经常用到引用,运算符重载专题
返回值是基础类型,当引用
int getAA1()
{
int a;
a=10;
return a;
}
//基础类型a返回时,也会有一个副本
int& getAA2()
{
int a;
a=10;
return a;
}
int* getAA3()
{
int a;
a=10;
return &a;
}
void main()
{
int a1=0;
int a2=0;
a1=getAA1();
a2=getAA2();//10
int &a3=getAA2();
printf("a1:%d \n",a1);
printf("a2:%d \n",a2);
printf("a3:%d \n",a3);
cout<<"hello..."<<endl;
}
返回值是static变量,变量是一个状态变量
//static修饰变量的时候,变量是一个状态变量
int j()
{
static int a=10;
a++;
printf("a:%d\n",a);
return a;
}