C++学习第三天

类和组合

对象数组和对象指针

可以进行定义对象数组对象指针
一维对象数组定义方法
类名 数组名[下标表达式];
类名 数组名[下标表达式]={类名(…),类名(…)};
//第一种默认调用系统给的无参构造函数
//第二种通过后面{}决定

class A
{int x,y;
public:
   A(){x=0,y=0;}
   A(int x,int j=0){x=i,y=j;}
 };
 如果这样定义的话
 A obj[4]={1,2};
 //如何传递?obj[0]出态为x=1,y=0
            //obj[1]初态为x=2,y=0

对象数组成员的引用同样注意限制性
————————————————————
对象指针
对象所占据的内存空间用于存放数据成员,对象的存储空间的起始地址就是对象的指针!!! 定义方法
类名 *对象指针名
访问方法

(*对象指针名).成员名
对象指针名->成员名
!!但要注意访问是否合法还要保证访问成员是公有成员!!

所有指针必须先赋值才能被使用

!!对象指针也是指针 和其他指针使用方法是一样的!!

this指针----自引用指针
①当对象被赋初值之后,就会出现一个隐藏的指针,这个对象的this指针就??指向!!内存中保存该对象数据的存储空间的首地址
②另外在类的成员函数中是可以使用这个this 指针的

class CMyclass
{ private:
    CMyclass *this;
    ...
   public:
    CMyClass(){...}
    ...
 };

一般不使用 使用的话就是需要在成员函数的实现中访问this所指的对象本身,而不是其各个成员
比较不错的例子 理解this指针

#include<iostream.h>
class ThisSample
{ int n;
public:
   void SetValue(int m){n=m;}
   void AddValue(int m)
   {ThisSample q;//函数内部临时对象????
    //???
   q.n=n+m;//n相当于this->n n+m赋给了q.n
   *this=q;//把q复制给this指针所指的那个对象
   //没调用复制构造函数
   }
   void Display()
   {cout<<"n="<<n<<endl;}
 void main()
 { ThisSample s;
   s.SetValue(10);
   s.Display();
   s.AddValue(5);
   s.Display();
  }

————————————————————
类的组合
就是类中内嵌对象成员
面向对象:复杂对象进行分解抽象,复杂对象分解为简单对象的组合。

对象成员的初始化
成员初始化列表:
例 CPoint::CPoint(int xx,int yy):x(xx),y(yy)
{cout<<“constructor called”;}

!调用构造函数时先执行成员初始化列表 再按顺序执行构造函数体内语句
!与说明普通对象不同,在说明对象成员时并没有创建该对象,等创建外层类的实例时会为对象成员分配内存初始化
!类中有对象成员,先执行所有对象成员构造函数,再执行当前类的构造函数体

代码理解:

class CPoint
{private: 
int x,y;
 public:
CPoint(int i=0,int j=0){x=i,y=j;}
CPoint(CPoint &p);
int getx(){return x;}
int gety(){return y;}
};
CPoint::CPoint(CPoint &p)
{x=p.x;y=p.y;
 cout<<"复制构造函数调用"<<endl;
 }
 
class CDistance
{ private:
   CPoint p1,p2;
   double dist;
  public:
     CDistance(CPoint xp1,CPoint xp2);
};
//进行构造函数的定义
CDistance::CDistance(CPoint xp1,CPoint xp2):p1(xp1),p2(xp2)//成员初始化列表
{ cout<<"CDistance构造函数被调用"<<endl;
  double x=1;
  double y=2;
}

void main()
{CPoint myp1(1,1),myp2(4,5);
 CDistance myd(myp2,myp2);
 }
    思考:怎么输出呢??
 Thought:
    main函数先定义了两个类对象
    
    其次进行CDistance初始化
    CDistance构造函数是怎样被调用的呢?
    
    NO.1:首先进行形实结合 把myp1 myp2赋给
    构造函数的形参xp1 xp2 
    ==这时会自动调用CPoint的复制构造函数==
    NO.2:接下来出现在成员初始化列表中,用已存在的xp1,xp2对象初始化成员初始化列表中的形参

—————————————————————————
位运算
按位与(&) 按位或(||) 按位抑或 按位取反 移位
C++中有两个移位运算符:左移运算(<<)和右移运算(>>),都是二元运算符。
左移是按照指定的位数将一个数的二进制值向左移位,左移后,低位补0,移出的高位舍弃。
右移是按照指定的位数将一个数的二进制向右移位,右移后移出的低位舍弃,如果是无符号数则高位补0;如果是有符号数,则高位补符号位
① 例:一int型变量a的值为-8,则a在内存中的二进制补码值为11111000,于是表达式a>>2的值为-2,补码变为11111110,对应值为-2
②例:表达式2<<1的值为4,移位前2的补码值为:00000010,移位后补码变为000000100,值为4

移位运算的结果是位运算表达式(a>>2和2<<1)的值,移位运算符左边表达式的变量值并不会改变

——————————————————————————

静态数据成员的声明和使用:
类中声明 例:static int total;
类外进行(必须) int CPoint::total=0;
【不能在构造函数中初始化 理解下】

访问:
①公有的: 类名::对象名. 引用
②私有的:只能在类内引用,类外没法用(因为是私有的)

静态成员函数
声明:
前面加static

访问:
①类名:: 访问
②对象名. 访问

说明:
静态成员函数可以直接引用该类的静态数据成员函数,而不能直接引用非静态数据成员
(静态成员函数定义类就存在了 非静态数据成员实例化对象时才存在 可以这么理解吧)

静态成员函数引用非静态数据成员,通过参数传递得到对象名,通过对象名引用间接实现

class CTest
{int x;
public:
  static void f(CTest a)
  { cout<<x<<endl;//错误!
    cout<<a.x<<endl;
  }
 };

静态成员函数无this指针

练习
#include<iostream.h>
class CPoint
{ int x,y;
  static int n;
  public:
  构造函数
  CPoint(int xx=0,int yy=0)
  {x=xx;y=yy;n++;}
  复制构造函数
  CPoint(CPoint &p)
  {x=p.x;y=p.y;n++;}
  析构函数
  ~CPoint(){n--;}
  int get_x(){return x;}
  int get_y(){return y;}
  静态函数
  static void get_n()
  {coun<<"obj"<<n<<endl;}
};
  静态数据成员初始化
  int CPoint::n=0;

————————————————————————————

友元

【B类内嵌A类对象,但是B的成员函数没法直接访问A的私有成员】
友元:
<1>某类中嵌套一个类,该类普通成员函数可以访问那个类中的数据
<2>一个普通函数可以访问那个类中的数据

实现
①友元函数(普通函数+其他类的成员函数)
<1>friend <类型标识符> <友元函数名>(参数表)
<2>friend <类型标识符> 类名:: <友元函数名>(参数表)

②简单使用 普通函数
<1>

class CPoint
{ double x,y;
public
  CPoint(double xx=0,double yy=0)
  {x=xx;y=yy;}
  double getx(){return x;}
  double gety(){return y;}
  //声明,在哪声明都行。这样想,它只是我的朋友,故不是本类的成员函数
  //所以放哪声明都行,跟类无关,只是为了用它来访问类中私有数据
  friend double get_distance(CPoint &p1,CPoint &p2);
};
double get_distance(CPoint &p1,CPoint &p2)
{ 
//传对象引用可以访问私有数据和公有数据
//!!这时候是友元函数起作用!!
return p1.x+p1.y+p2.x+p2.y;
}
void main()
{
CPoint my(1,1),my2(1,1);
//调用也是直接调用,因为这个函数只是那个类的朋友,不是本类的成员函数
cout<<"cout"<<get_distance(my,my2);
}

<2>(跟<1>差不多)

class CPoint
{ double x,y;
public
  CPoint(double xx=0,double yy=0)
  {x=xx;y=yy;}
  double getx(){return x;}
  double gety(){return y;}
  friend double get_distance();
};
double get_distance()
{ CPoint p1(1,2);
CPoint p2(2,3)
return p1.x+p1.y+p2.x+p2.y;
}
//调用也是直接调用,因为这个函数只是那个类的朋友,不是本类的成员函数

③简单使用(感觉知道就行) 其他类的成员函数

class CPoint;
class CTest
{ ...
 friend double get_distance(CPoint &p1,CPoint &p2);
  ...
};
class CPoint
{
CPoint p1;
CPoint p2;
//声明
friend double CTest::get_distance(CPoint &p1,CPoint &p2);
}double CTest::get_distance(CPoint &p1,CPoint &p2)
{
...
}
//调用不是直接调用,得先构造CTest对象,通过**对象.**的形式调用。

总结:
其实差不多,A类中的友元函数可以是普通的函数,也可以是其他类的函数,不同情况对应不同的声明,只要明白一点,友元函数不属于A类本身,它只是用于调用A类的私有数据成员罢了,这时刻记住。

④简单实用 友元类
friend class <友元类名>
其实就是范围扩大了,A类为B类友元类,就在B类中声明:friend class A;,A类就是B类的朋友了,A类中所有函数,数据成员对于B类中的私有数据啥的都能访问,③扩展

class CPoint;
class CTest
{ ...
  double get_distance(CPoint &p1,CPoint &p2);
  void test(CPoint &p1);
  ...
};

class CPoint
{
CPoint p1;
CPoint p2;
//声明友元类
friend class CTest;
}//调用不是直接调用,得先构造CTest对象,通过**对象.**的形式调用。

总结:
分为友元类和友元函数 懂得如何去理解
————————————————————————————

常类型

const修饰符
例:#define的不安全性

#include<iostream>
using namespace std;
main() {
    int a=1;
    //define只是字面替换 在预编译时进行了字符替换
    #define T1 a+a
    #define T2 T1-T1
    cout<<"T2 is "<<T2<<endl;
    return 0;
        }
  //输出结果为T2 is 2

const使用

#include<iostream>
using namespace std;
main() {
    int a=1;
    //这个常量是有类型 占用存储单元,有地址,可以用指针指向它
    const T1=a+a
    const T2=T1-T1
    cout<<"T2 is "<<T2<<endl;
    return 0;
        }
  //输出结果 T2 is 0

const与指针组合使用

//(1)常量指针:是指*指针变量**指向**常量**的*。
const char *pc="abcd";//声明指向**常量**的指针
    右左法则(pc is a pointer to const char)
pc[3]="X";//编译时出现错误
pc="efgh"//正确,指针本身是一个**变量**

//(2)指针常量:是指**指针的常量**,指向**变量**的。
char * const pc="abcd"; //指针常量 必须在声明的时候进行初始化 
   右左法则   (pc is a const point to character)
pc[3]="x";//正确
pc="efgh";//编译时出现错误

//(3)指向常量的指针常量:指针是一个常量(不可以修改指向,指针指向的也是一个常量)
const char *const p="abcd";

const修饰做函数形参

//const <类型标识符> &<引用名>
void display(const int &r)
{
 cout<<"r="<<++r<<endl;
 //错误! 常引用没法改变
}
//有时会用到 这个应该用的比较多

const对象 const函数(知道就行)

const <类名> <对象名>
//必须同时初始化 实例化对象啥都没法改变(数据成员)
//声明const对象有啥用? 好像没啥用
void diaplay() const;
//const对象可以调用const修饰的成员函数。。
//用的少 开发可能用

说明:如果const修饰int型常量,则关键字int可以省去。
常量一旦建立,程序中任何地方则不能再改
const常量可以有自己的数据类型
函数参数也可以用const说明,用于保证实参在该函数内部不能改动

——————————————————————————

动态内存分配

C语言中动态内存分配有malloc colloc函数吧
1. new运算符
char CBuffer = new char[256];*
*CBuffer[1]=‘a’;
(CBuffer+5)=‘c’;

–成功:T类型的指针,指向新分配的内存 并且分配的内存空间是连续的
–失败:0(NULL)


2.delete运算符  就是释放内存
int *pInt = new int;
delete pInt;//删除单个指针**
char *CBuffer = new char[256];
delete []CBuffer;
3.面向对象中
class R
{ 
R(){ }
};

void main()
{
 R  *p;
 p=new R();
 cout<<p->area()<<endl;
 //Java中摒弃了指针 多好。。
 delete p;
 //释放p指向的内存空间 会调用析构函数
}

**说明:**delete删除的只能是new运算符创建的对象
这两使用比较灵活

发布了19 篇原创文章 · 获赞 2 · 访问量 747

猜你喜欢

转载自blog.csdn.net/qq_45639157/article/details/104702005