初识C++ 类(上篇)

115 篇文章 1 订阅
111 篇文章 1 订阅

CSDN话题挑战赛第1期

活动详情地址:https://marketing.csdn.net/p/bb5081d88a77db8d6ef45bb7b6ef3d7f

参赛话题:大学生竞赛指南

话题描述:本话题聚焦于大学生竞赛心得体会分享,对于计算机众多领域每年都有很多都会举办科技竞赛,很多学生也都会踊跃参与,每到竞赛结束,学生们都会收获很多,这个时候我们可以写下一篇竞赛心得,大家互相交流学习科技竞赛经验,共同分享竞赛资源、探讨各领域技术以及比赛技巧,希望大家能够在此话题下一起讨论一起学习,能够探索一个属于自己的大学竞赛生活。

文章目录

写在前面

不行,我有点激动,总算到类了,这真是不容易.可以这么说,我们一旦学习到了了类,自己的知识便可以抬高一个台阶,类是我们面向对象的基础,我现在难以表述我对它的感情.这个博客主要是初步认识一下类,至于细节,后面的几篇博客都会详细分享.不说了,让我们扬帆起航.

类&对象

类和对象是我们学习面向对象语言的基础,它太重要的了.

什么是类

我们先看看定义,花里胡哨的.

类(英语:class)在面向对象编程中是一种面向对象计算机编程语言的构造,是创建对象的蓝图,描述了所创建的对象共同的特性和方法。
支持类的编程语言在支持与类相关的各种特性方面都多多少少有一些微妙的差异。大多数都持不同形式的类继承。许多语言还支持提供封装性的特性,比如访问修饰符。类的出现,为面向对象编程的三个最重要的特性(封装性、继承性、多态性),提供了实现的手段。 来源:(维基百科)

说人话,就是我们把一些变量和函数放到一个集合里面,这个集合存在一定的规则,叫做类.后面我们可以通过类来实例化对象,这个我们后面再分享.

为何要有类

我们之前在学习数据结构的时候,自己定义了结构体和函数是分开的,这种行为有一定的缺陷,太自由了,所以聪明的程序员想到能不能把这些方法和要使用的变量写在一起,用的时候直接拿出来就可以了,这就是类的由来.

如何定义类

我们可以这么理解,C++在一定程度上是填C语言的一些坑,我们在C语言中学习过结构体,但是里面只能定义变量,C++可以定义一些函数,由此这个结构体就进化成了类.

下面就是一个类.

struct Person
{
	void print()
	{
		cout << "我叫" << _name << ",今年" << _age << "岁了";
		cout << endl;
	}

	void set(const char* name, int age)
	{
		_age = age;
		strcpy(_name, name);
	}

	int _age;
	char _name[20];
};

也就是说类就是在结构体里面加入一些函数.

但是在C++中定义类,又出现了一个关键字,calss,至于它和strcut定义类的区别,我们后面会谈到.

class Person
{

};

什么是对象

在计算机科学中,对象(英语:object),台湾译作 " 物件 ",是一个存储器地址,其中拥有值,这个地址可能有标识符指向此处。对象可以是一个变量,一个数据结构,或是一个函数。是面向对象(Object Oriented)中的术语,既表示客观世界问题空间(Namespace)中的某个具体的事物,又表示软件系统解空间中的基本元素。
在软件系统中,对象具有唯一的标识符,对象包括属性(Properties)和方法(Methods),属性就是需要记忆的信息,方法就是对象能够提供的服务。在面向对象(Object Oriented)的软件中,对象(Object)是某一个类(Class)的实例(Instance)。 来源:维基百科

总结一句话就是下面的

  • 类就是一个模子 我们根据这个模子来造东西
  • 对象就是一个实体,我们通过模子构造出的实体

实例化一个对象

在C++中,类名自己就可以代表一个类型,不需要加入struct了,但是加入了也可以.

int main()
{
	struct Person person1;
	Person person2;       // 可以把  struct 去掉
	
	return 0;
}

类的组成

前面我们是初步的了解一下类,这才是今天的重头戏.我们需要一笔一笔的解剖类的知识.

struct Person
{
	void print()
	{
		cout << "我叫" << _name << ",今年" << _age << "岁了";
		cout << endl;
	}

	void set(const char* name, int age)
	{
		_age = age;
		strcpy(_name, name);
	}

	int _age;
	char _name[20];
};

类的组成分为下面两种.

  • 字段 有的时候也称成员变量,属性
  • 方法 类里面的函数称为类的方法或者成员函数

字段

所谓的字段就是里面的一些变量,下一篇博客会专门和大家详细的分享.

int _age,char _name[20];就是字段

方法

里面我们定义的函数,print(),set()就是方法.C++里面的方法属于类,不属于对象.

方法 & 函数

在C语言中,我们一般称为函数,但是C++里面,我比较喜欢称为方法,我也不太明白它们区别,在网上找了一部分的,这里给出一个解决方法.类里面叫方法,类外面叫函数.大家也别纠结了,这都是小问题.

访问修饰限定符

这个很重要,可惜现在我们不能在这里细说,不过也不要着急.

  • 共有的 public 类外面可以使用

  • 私有的 private 只能在类里面使用

  • 受保护的 protected 继承的时候再说

    class Person
    {
    public:
    void print()
    {
    cout << “我叫” << _name << “,今年” << _age << “岁了”;
    cout << endl;
    }

    void set(const char* name, int age)
    {
    	_age = age;
    	strcpy(_name, name);
    }
    

    private:
    int _age;
    char _name[20];
    };

所谓的访问修饰限定符就是权限的问题,这里我不会详细的说.

访问修饰限定符的范围

访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止 ,这样就避免了多次使用同一个限定符,麻烦.

image-20220514203844927

class & struct

既然struct和calss都可以定义类,那么它们具有什么不同.首先我们要明白一点,class是C++中常用的,它们的区别并不大.

如果没有加 访问修饰限定符,calss里面的方法和属性默认都是是private的,而public默认是共有的

C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。
和class是定义类是一样的,区别是struct的成员默认访问方式是public,class是的成员默认访问方式是
private。

class Person
{
	void print()
	{
		cout << "我叫" << _name << ",今年" << _age << "岁了";
		cout << endl;
	}

	void set(const char* name, int age)
	{
		_age = age;
		strcpy(_name, name);
	}
private:
	int _age;
	char _name[20];
};

struct Student
{
	void print()
	{
		cout << "我叫" << _name << ",今年" << _age << "岁了";
		cout << endl;
	}

	void set(const char* name, int age)
	{
		_age = age;
		strcpy(_name, name);
	}
private:
	int _age;
	char _name[20];
};

int main()
{
	//  class  创建
	Person person;
	person.set("qkj", 18);
	person.print();

	//  struct  创建
	Student student;
	student.set("zhansan", 19);
	student.print();
	return 0;
}

image-20220514205222585

类对象的大小

我们知道结构体的大小计算方法,那么请问类的大小是什么计算我们要不要把函数看作给一个指针还是不做计算呢

我们先来看看现象.

从这里就可以看出来,我们不计算函数的大小,只计算属性,类的计算方法和结构体的一样,也遵循内存对齐.

class Student
{
	void print()
	{
		cout << "我叫" << _name << ",今年" << _age << "岁了";
		cout << endl;
	}

	void set(const char* name, int age)
	{
		_age = age;
		strcpy(_name, name);
	}
private:
	int _age;
	char _name[20];
};

int main()
{
	cout << sizeof(Student) << endl;
	return 0;
}

image-20220514212123252

为何不计算方法的内存

想一想,假如我们计算函数的大小,那么也就意味着我们每实例化一个对象,都需要给这个的函数开辟空间,我们如果实例化的对象太过,那么内存开辟的不久太多了吗所以一个类里面的方法只会开辟一个空间,无论实例化多少次这个类,方法只会开辟一次,那么这个方法的空间计算就会有一定的纠纷,所以就不计算了.

int main()
{
	Student stu1;
	stu1.set("qkj", 18);

	Student stu2;
	stu2.set("qkj", 18);
	return 0;
}

image-20220514213619265

空类

我们知道了类的大小的计算方法,那么下面的类的大小是多少它是一个空类,大小是不是应该是0实际上不是的,编译器把它的大小给成1字节,先作为一个占位符先占着,告诉编译器存在一个这样的类.

class B
{

};

image-20220516123904121

类何时开辟空间

这里我们需要说一下就可以了,我们实例化对象的时候才会出现开辟空间.存在在类里面的属性是一个声明,不开辟空间.

int main()
{
	Student stu1;
	stu1.set("qkj", 18);
	return 0;
}

image-20220514213919048

this 指针

到这里我们可以知道到了,既然方法是不属于对象,属于类的,那么编译器是如何可以确定对象调用的方法一定是正确的呢

编译器是如何确定对象可以调用正确的方法呢

在代码运行的时候,编译器会自动把对象的地址作为个参数传给函数,这样,函数就可可以准确调用,这是编译器自动处理了,我们不能显示处理,这样不久抢了编译器的活吗!!!

class Person
{
public :

	void print()
	{
		cout << "我叫" << _name << ",今年" << _age << "岁了";
		cout << endl;
	}

	void set(const char* name, int age)
	{
		_age = age;
		strcpy(_name, name);
	}
private:

	int _age;
	char _name[20];
};

int main()
{
	Person per1;
	per1.set("张三",18);
	Person per2;
	per2.set("李四",20);

	per1.print();
	per2.print();
	return 0;
}

image-20220516121019111

image-20220516120134182

实际上,编译器会在函数调用的时候给函数一个优化,我先给大家写一写,一看就可以明白了.

void print()
{
    cout << "我叫" <<_name << ",今年" << _age << "岁了";
    cout << endl;
}


void print(Person* this)
{
    cout << "我叫" << this->_name << ",今年" << this->_age << "岁了";
    cout << endl;
}

image-20220516120742976

this

前面我们看到了this这个关键字,在对象里面表示当前对象的地址.

class A
{
public:
	void print()
	{
		cout << "this " << this << endl;
	}
};

int main()
{
	A a;
	a.print();
	cout << "&a   " << &a << endl;
	return 0;
}

image-20220516121958502

也就是说,我们前面写打印函数可以这样写,不过我不太建议,既然编译器帮我们做了,我们就不需要了,不过大家要看自己公司的代码规范要求.

void print()
{
    cout << "我叫" << this->_name << ",今年" << this->_age << "岁了";
    cout << endl;
}
  1. this指针的类型:类类型* const
  2. 只能在“成员函数”的内部使用
  3. this指针本质上其实是一个成员函数的形参,是对象调用成员函数时,将对象地址作为实参传递给this
    形参。所以对象中不存储this指针
  4. this指针是成员函数第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户
    传递

this指针存在哪里

既然this指针作为一个形参,那么它就是存储在栈区中了,不过有的编译器会优化,把它存在寄存器中.

image-20220516125648831

this指针可以为空吗

可以为空的

class B
{
public:

	void print()
	{
		cout <<  this << endl;
	}
};

int main()
{
	B* b = nullptr;
	b->print();
	return 0;
}

image-20220516125428908


多文件 中使用类

多文件是我们写大型程序的的基础,我们需要使用类.我们需要好好的谈谈的这个东西.我们可以在类体里面声明和定义方法,但是成员函数如果在类中定义,编译器可能会将其当成内联函数处理.

一般情况下,我们是在头文件里面声明类,在类里面声明属性和方法,方法的实现是在另一个文件里面.我们一般都是这么实现的.

// test.h
#include <iostream>
using namespace std;

class Person
{

	void print();
    void set(const char* name, int age);
	
	int _age;
	char _name[20];
};

//test.cpp

#include "test.h"
void Person::print()
{
	cout << "我叫" << _name << ",今年" << _age << "岁了";
	cout << endl;
}

void Person::set(const char* name, int age)
{
	_age = age;
	strcpy(_name, name);
}

image-20220514211113084

CSDN话题挑战赛第1期

活动详情地址:https://marketing.csdn.net/p/bb5081d88a77db8d6ef45bb7b6ef3d7f

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值