C++学习笔记02
指针
用来保存某种类型的变量的地址的变量,取地址& ->知道变量取地址,某个地址的变量: *地址
成员指针,(*地址).成员,地址->成员
向函数传递参数的时候,如果希望函数能操作某个变量里的数据,就把变量的地址传递给函数,函数里就可以根据地址找到内存中的那个变量,从而取得或者改变变量里的值。
地址运算
+n,-n 始终与地址的类型为单位来走,例如整形移动4*n个字节 p+n,p-n
P[i] ==> *(p+i)
#include<iostream> using namespace std; int main() { int a[5] = {11,12,13,14,15}; int *p = a; cout<< a[2] << ','<<p[2]<<endl; cout<< *(a+2) << ','<< *(p+2)<<endl; cout<< 2[a] << ','<< 2[p] <<endl; system("pause"); return 0; }
p-q结果是多少个单位,单位为sizeof(地址类型),比较
指针定义时建议带初始化从而避免野指针,不要通过空指针或目标已经释放掉的指针去找变量(*),不要返回非静态局部变量的地址作为函数的返回值,作为函数形参的指针如果不用于改变目标的值就尽量加const修饰保护目标不被误伤。
X const *p <==> const X *p; p指向的只读X类型的数据
函数指针
int f1(char* ,int) -> int (*p) (char* int);
数组指针
int a[8]; ->int (*p)[8]
输出地址:
输出字符类型的地址,为了保持与C语言的兼容,系统处理成输出字符串
#include<iostream> using namespace std; int main() { char c = 'a'; char *p = &c; int i= 1; int *q = &i; cout << p <<','<<q<<endl; system("pause"); return 0; }
引用
引用一个常亮应该对引用加const.用临时结果(运算结果或者函数的普通返回值)去初始化一个引用时,也应该对引用加const
const int x=20;
const int& rx = x;
面向对象 Object-Oriented Programming
C语言是一系列的函数描述程序的工作过程,称为过程。
C++把程序里面的数据和对数据的操作合起来看作一个实体称为对象,编程工作就是操纵这些对象相互作用来完成程序的功能,这样的编程方式称为面向对象。
抽象:每个实体都有很多的数据和很多的行为,只提取咱们关心的数据和行为。
封装:用抽象的结果来描述实体的类型,在C++中可以用结构来实现封装,但出于跟C语言的兼容一般在C++结构也只封装数据,用class关键字来实现真正的封装,封装后的东西称为类。
*********************封装好的类/结构只是一个类型***************************
定义类:
class xxx{
成员变量或者成员函数的定义
};
结构与类的区别
结构默认情况下就是一个简单打包,内容对外是透明的,可以通过结构变量名访问它的任何一个成员。
类默认是保密封装,对外是不透明的,不允许通过变量直接访问它的成员,除非是故意公开的(public),一般公开的都是函数
这种类或者结构类型的变量(实例)就称之为对象
#include <iostream> using namespace std; struct sDate{//全部成员默认公开 int year; int mouth; int day; void set(int y,int m,int d){ year= y,mouth= m,day=d; } void print(){ cout<<year<<'-'<<mouth<<'-'<<day<<endl; } }; class cDate{//默认不公开,private int year; int mouth; int day; public: //以下部分公开,若未公开则无法访问 void set(int y,int m,int d){ year= y,mouth= m,day=d; } void print(){ cout<<year<<'-'<<mouth<<'-'<<day<<endl; } }; int main() { sDate s;//定义对象s cDate c;//定义对象c s.set(2012,12,21);//使用对象 c.set(2016,4,28);//使用对象 s.print(); c.print(); system("pause"); return 0; }
成员函数如果在外面实现(函数体不在这个类的内部),那么函数名应该写成“类名::函数名”。结构也是如此
多文件结构:一个类一般写成一个.h文件和一个.cpp文件,在.h文件中,成员函数只有声明,没有函数体,在.cpp文件中包含.h文件并且给出那些成员函数的定义(包括函数体)
myclass.h:
#ifndef MY_CLASS_DEFANT struct sDate{ int year; int mouth; int day; void set(int y,int m,int d); void print(); }; class cDate{ int year; int mouth; int day; public: //以下部分公开 void set(int y,int m,int d); void print(); }; #endif
myclass.cpp
#include<iostream> using namespace std; #include "myclass.h" void sDate::set(int y,int m,int d){ year= y,mouth= m,day=d; } void sDate::print(){ cout<<year<<'-'<<mouth<<'-'<<day<<endl; } void cDate::set(int y,int m,int d){ year= y,mouth= m,day=d; } void cDate::print(){ cout<<year<<'-'<<mouth<<'-'<<day<<endl; }
main.cpp
#include <iostream> using namespace std; #include "myclass.h" int main() { sDate s; cDate c; s.set(2012,12,21); c.set(2016,4,28); s.print(); c.print(); system("pause"); return 0; };
构造函数
创建每一个对象时会自动调用一个成员函数,函数名就是类名,无返回类型。
构造函数可以重载,一般访问限制为公开
创建对象如果不传参数,不要带空括号,否则会被认为是函数声明
如果一个类没有构造函数,编译器会自动为它产生一个不干事的空函数,只要有构造函数了编译器就不会再为这个类产生这个无参构造函数(默认构造函数、缺省构造函数)
一个对象在创建的时候需要做额外的事情,就可以放在构造函数里面。
#include<iostream> #include <string> using namespace std; class Cat{ public: Cat(){cout<<"call Cat()" <<endl;} Cat(string s) {cout<<s<<"猫闪亮登场!"<<endl;} }; class Dog{ public: Dog(){cout<<"call Dog()" <<endl;} Dog(string s) {cout<<s<<"犬横空出世!"<<endl;} }; int main() { Cat c;//自动调用无参构造函数 Dog d; Cat c2("加菲");//自动调用带string参数的构造函数 Dog d2("贵宾");
Cat c3();// *特别注意* 声明一个函数c3,返回类型Cat,参数表空,并非实例化一个对象 system("pause"); return 0; }
创建对象的步骤:
分配内存
执行构造函数
如果成员是对象,成员的构造函数会在整体的构造函数之前执行
调用成员函数时编译器会把传一个隐藏的参数对象的地址进去
this
调用成员函数时,编译器总是自动悄悄把点它的那个对象的地址作为一个隐含参数传递,在成员函数的内部,用关键字this来接受这个隐含参数,类型为X* const,表示当前对象的地址
#include<iostream> using namespace std; #include<string> int thisyear; class Person{ string name; int year; bool gender; Person* lover; public: Person(const string& name,bool gender){ Person::name = name; Person::gender = gender; year = thisyear; lover = NULL; } void show(){ cout<<"我是"<<(gender?"帅哥":"美女")<<name<<",今年"<<thisyear-year<<"岁"; if(lover) cout<<",跟"<<lover->name<<"恋爱中"<<endl; else cout<<",单身"<<endl; } void Love(Person* x){ //Person* const this接受隐含参数指向当前对象 Person::lover = x; x->lover = this; } void Leave(){ lover = lover->lover=NULL; } }; int main() { thisyear = 1990; Person a("李钊",true); thisyear = 1992; Person b("芙蓉",false); thisyear = 2013; a.show();//传递隐含参数 a.show(&a) b.show(); thisyear = 2015 ; a.Love(&b); a.show(); b.show(); thisyear = 2016; a.Leave(); a.show(); b.show(); system("pause"); return 0; }