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

本文深入探讨了C++中的类与对象概念,包括this指针的作用与内存结构分布、构造与析构函数的使用、拷贝构造函数的实现、初始化列表的应用以及static和const关键字的特性。此外,还介绍了友元函数和友元类的概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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的友元,同样要看类中是否有相应的申明

内容概要:本文档主要展示了C语言中关于字符串处理、指针操作以及动态内存分配的相关代码示例。首先介绍了如何实现键值对(“key=value”)字符串的解析,包括去除多余空格和根据键获取对应值的功能,并提供了相应的测试用例。接着演示了从给定字符串中分离出奇偶位置字符的方法,并将结果分别存储到两个不同的缓冲区中。此外,还探讨了常量(const)修饰符在变量和指针中的应用规则,解释了不同型指针的区别及其使用场景。最后,详细讲解了如何动态分配二维字符数组,并实现了对这数组的排序释放操作。 适合人群:具有C语言基础的程序员或计算机科学相关专业的学生,尤其是那些希望深入理解字符串处理、指针操作以及动态内存管理机制的学习者。 使用场景及目标:①掌握如何高效地解析键值对字符串并去除其中的空白字符;②学会编写能够正确处理奇偶索引字符的函数;③理解const修饰符的作用范围及其对程序逻辑的影响;④熟悉动态分配二维字符数组的技术,并能对其进行有效的排序和清理。 阅读建议:由于本资源涉及较多底层概念和技术细节,建议读者先复习C语言基础知识,特别是指针和内存管理部分。在学习过程中,可以尝试动手编写似的代码片段,以便更好地理解和掌握文中所介绍的各种技巧。同时,注意观察代码注释,它们对于理解复杂逻辑非常有帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值