类与对象(附加)---day3

1、this指针与类与对象的内存结构分布

1)this指针定义在类的方法中

2)是隐性的指针

3)创建类对象之后,this指针没有具体指向哪里,如果不调用类的方法,,this指针不会指向操作函数。

当类对象调用类的方法去操作本身内存空间时,this指针会指向这个类的对象。

4)是属于类的唯一的一个指针,在对不同的类对象操作时会实时切换。

app.h

#ifndef APP_H
#define APP_H
 
#include <iostream>
using namespace std;
 
class point
{
private:
    int x;
    int y;
public:            //操作方法一般都设为公有,被外部函数调用
//普通的类的成员函数
    void setxy(int a,int b)
    {
        this->x=a;   //this指针是隐藏的,可以不用写
        this->y=b;
    }
    void disxy()
    {
        cout<<"x= "<<x<<endl;
        cout<<"y= "<<y<<endl;
    }
};
 
 
#endif // APP_H
 类是存在test段, 

main.cpp

#include"app.h"

int main()
{
    cout << "Hello World!" << endl;
    point p;      //分配一段内存空间,没有内容,需要初始化
    p.setxy(18,27);
    p.disxy();
 
    return 0;
}
 

p是个数据类型,局部变量。执行point p语句根据类的数据成员为p分配内存空间。可以用size查看空间大小。

p.setxy是一个代码的起始地址。

2、构造与折构函数(拷贝构造)

2.1构造函数:是用来对类的对象的内存中的变量进行初始化

#include <iostream>
using namespace std;
 
class point
{
private:
    int x;
    int y;
public:
    //定义了一个类的构造函数,用于初始化
    point (int a,int b)
    {
        cout<<"constructor"<<endl;
        x=a;
        y=b;
    }
    /*
    void setxy(int a,int b)
    {
        this->x=a;
        this->y=b;
    }*/
    void disxy()
    {
        cout<<"x= "<<x<<endl;
        cout<<"y= "<<y<<endl;
    }
};
 
int main()
{
    cout << "Hello World!" << endl;
    point p(20,90); //直接调用类的构造函数
    //p.setxy(18,27);
    p.disxy();
 
    return 0;
}
 
 
输出: 
constructor 

x=20

y=90

特点:1)定义的构造函数,会对类对象创建时自动调用构造对对类对象成员进行初始化

   2)函数名跟类名要一样

   3)没有返回值

   4)如果定义在类外,也要加上类从属关系

   5)构造函数可以重载(函数名一样,但传参不同)

   何为重载:示例

	point()
    	{
       		cout<<"no param"<<endl;
       		x=66;
        	y=45;
   	}
   	point(int a)
    	{
        	cout<<"one param"<<endl;
        	x=a;
        	y=88;
    	}
    	point (int a,int b)
    	{
        	cout<<"constructor"<<endl;
        	x=a;
        	y=b;
    	}

point p;

p.disxy();

创建类对象的时候会在类中查找构建函数,如果没有定义构造函数,系统会自动分配一个无传参的构造函数。运行的时候不会报错。如果有,传参不一样会出现报错。


2.2析构函数:对已经存在的类对象的内存进行清除处理

 	~point()//在类里面定义析构函数
    	{
        	cout<<"clean all"<<endl;
    	}

1)无传参,无返回值,但是要带一个“~”声明是析构

2)每调用一次构造函数创建一个类对象,就一定会在退出前自动调用析构函数来清除这个对象内存。

3)如果类没有定义析构函数,系统也会自动分配一个析构函数。

2.3拷贝构造函数

1)将一个变量的内容拷贝过程,初始化到新的变量的过程

类里面定义拷贝构造函数

point(const point &p)

{

cout<<"copy construnstor"<<endl;

x=p.x+11;

y=p.y+44;

   }

point p2 = p1; 或者point p2(p1);都是调用了上面的函数

2.4深浅拷贝构造函数

1)浅拷贝vs深拷贝

char *pdest; //指针指向一块内存地址,可能有内容。(类成员)

 main.cpp:	point p2 = p1; //拷贝函数

    // 定义一个拷贝构造函数
    point(const point &p)
    {
        cout<<"copy constructor"<<endl;
        xres = p.xres;
        yres = p.yres;


        //会使得p1与p2共享到同样一块内存,这种做法称为浅拷贝构造	
        //调试1:
        //pDest = p.pDest;
	
        //深拷贝做法
        //调试2:
        pDest = new char[strlen(p.pDest) + 1];
        if(pDest != 0)
        {
            strcpy(pDest, p.pDest);
        }
    }
	//析构函数需要释放内存
	~point()
    	{
        	cout<<"clean all"<<endl;
        	delete pdest;
   	}

浅拷贝隐藏bug,很少使用。


3、初始化列表

3.1类成员函数的实现

通过类对象调用类的成员函数,实现初始化。

p.setxy();

3.2构造函数实现

//用于初始化的构造函数

      point (int a,int b):x(a),y(b){}  //这样的形式,效率比较快

创建类对象时自动调用构造函数,实现初始化。

a.一个是构造,一个是普通成员函数

b.构造函数在分配内存空间的就初始化,而成员函数是先定义一个类的对象分配内存空间,再对成员初始化,频率是不一样的。

特点:更快实现对类对象的各个变量初始化

什么情况下会使用初始化列表?

    1.使用const声明的变量要初始化、

    2.使用引用声明的变量要初始化

const int x;

    3.派生类中要对基类部分内容进行初始化

class space:public point

{

private:

int z;

public:

void setz(int c);

}

space::space(int c):point(x,y)

{

z = c;

}

4、关键字分析

4.1static关键

1)可以用于声明类的数据成员

class point 

{

private:

int x;              //非静态数据成员

static int y;       //静态数据成员

}

如果static声明后,编译器会在编译时将这个变量连接到data段。

好处:在编译阶段就会被处理(分配得到自己的空间);

    放到data段,在加载后是独立存在的段,被所有的程序都可以访问到,相当于全局变量。

如何使用:

类外初始化

用static声明

可以直接使用:如果是private声明,只能通过类的公有函数操作;如果是public声明,可以直接通过类调用,也可以通过类的公有函数操作。

#ifndef INIT_H
#define INIT_H
#include<iostream>
#include<string>
using namespace std;
 
class computer
{
private:
    float unit_price;    //非静态成员函数
    //static float total_price;   //静态成员函数
public:
    static float total_price;
    computer(int price)
    {
        unit_price = price;
        total_price += price;
    }
    void disinfo()
    {
        cout<<"unit_price = "<<unit_price<<endl;
        cout<<"total_price = "<<total_price<<endl;
    }
 
};
 
float computer::total_price = 0;
 
#endif // INIT_H

int main()
{
    cout << "Hello World!" << endl;


    computer::total_price = 288; //直接通过类调用
    cout<<"total_price:"<<computer::total_price<<endl;
	
    computer p1;
    p1.disinfo(20);
    return 0;
}
 
2)可以用于声明类的成员函数 

与普通的成员函数相比,静态成员函数具有如下特点:

只能操作静态的成员(静态的数据成员与静态成员函数)

3)与全局变量相比较,用static声明有什么好处

a、具有全局变量的功能

b、具有很好的封装性,具有更高的安全性

4.2const关键字 

1)声明类的数据成员

const int id;(只读,不能修改),可以使用列表进行初始化。

student (int stuid, int s...) : id(stuid),sorce(s)

特点:a、必须使用初始化列表进行初始化

    b、只能使用成员函数读,不能写

    c、

2)声明类的成员函数

void set(string name) const

特点:

a、const函数只能读,不能有写的操作

b、可以被const类对象调用

3)声明类的对象

示例:const student stu 或者 student const stu

特点:

a、声明之后就是一个常量,不允许再修改。

b、可以使用构造函数进行构造

c、不能调用非const成员函数,可以调用const成员函数

........

5、友元操作

5.1 友元函数   一个变量包装成一个类里面的数据成员  ==> 类的封装性,具有很好的安全性      

class point   

{

private: 

int xres;

public:

void setx(int x)

{ 

xres = x;

}   

}     

 为了提高操作数据成员的效率,允许外面普通函数直接到类里面的数据进行操作,而不需要通过成员函数,这就是友元操作   这个普通函数必须得到类的认可。这个函数就是类的友元函数      如何将普通函数变成一个友元函数,并且访问类的数据成员      1. 得有一个类,类中定义数据成员   2. 得有一个普通函数   3. 在类中通过friend声明为类的友元函数   4. 直接在类外面,利用友元函数操作类里面的内容

#include <iostream>
#include <string>
using namespace std;
 
class student
{
private:
    string name;
    const int stuid;
    float score;
 
public:
    student(string n, int i, float s):name(n),stuid(i),score(s)
    {
    }
    friend void display(const student &s);
 
};
 
//一个普通函数
void display(const student &s)
{
    cout<<"name:"<<s.name<<endl;
    cout<<"stdid:"<<s.stuid<<endl;
    cout<<"score:"<<s.score<<endl;
}
 
int main()
{
    student stu("kitty", 102, 89);
    display(stu);
 
    return 0;
}
 

5、2友元类

#include<iostream>
#include<string>
using namespace std;
 
 
class space; //类space未定义之前就已经在类point中用到,需要提前声明,以防出错
 
class point
{
private:
    int xres;
    int yres;
    string name;
 
public:
    point(int x, int y, string n)
    {
        xres = x;
        yres = y;
        name = n;
    }
 
    // point成员函数
    void setname(space &s);   
 
 
    void display()
    {
        cout<<"point_name: "<<name<<endl;
    }
 
};
 
class space
{
private:
    int xres;
    int yres;
    int zres;
    string name;
public:
    space(int x, int y, int z, string n)
    {
        xres = x;
        yres = y;
        zres = z;
        name = n;
    }
    void display()
    {
        cout<<"space_name: "<<name<<endl;
    }
 
    //声明友元
    //friend void point::setname(space &s);
    friend class point;  //类point的所有成员函数都是类space的友元函数,能存取类space的私有成员和保护成员
 
 
};
 
void point::setname(space &s)
{
    name = "kitty";
    s.name = "pitter";
    //name = s.name;
}
int main()
{
    point p(10, 20, "yang");
    space s(100, 200, 300, "space");
 
    p.setname(s);
    p.display();
    s.display();
    return 0;
}

使用友元类时注意:

  (1) 友元关系不能被继承。 
  (2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。 
  (3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值