笔记4 · C++类和对象的创建与使用

类和对象式C++重要的特性,合理的使用类和对象可以用来开发大型的项目。

什么是类, 什么是对象?之前我在选修《Java程序设计基础》课中(我学的很烂,因为当时没有C的基础,所以听起来十分的吃力)提到:

世界万物都可以看作是一个类。

手机模型,机械图纸就可以看作是一个类。类是对象的模型,对象是类的实现。类是具有相同属性和方法的一组对象的组合。如:CPU、内存、显示器。

对象的属性:对象拥有相同的特征,并占用内存空间。每个对象的每个属性都共同拥有的特征值。如:CPU的主频、总线频率;显示屏的大小值,内存的大小值。

(类)对象的方法:对象的行为,如打电话,发短信。

个人认为在这些高级的面向对象式的编程语言,在概念上还是有很多共同点的。所以这里把它生动形象的描述借鉴过来,辅助理解记忆。

类与结构体一样,类是一种复杂的数据类型声明,不占用内存空间。而对象是类这种数据类型的一个变量,或者说是通过类这种数据类型创造出来的一份实实在在的数据,所以占用内存空间。

如何定义类:

//如何定义类?
class student{//class  <类名>
    private://访问权限private
        //成员变量
        char *m_name;
	int m_age;
	float m_score;

    public://访问权限public
        //成员方法
	void setname(char *name);
	void setage(int age);
	void setscore(float score);
	inline void show(void);
};

如上所示,就表示见识了一个C++类的定义。一个类就像定义结构体那样,有关键字class 有类名 还有两个大括号并且右括号后紧跟分号

结构体里包含基本数据类型定义出来的变量, 整个结构体被叫做---聚合类型,聚合类型是由多个基本类型(如int、char、double、float、short)等构成。

类,同理这么包含。包含一切结构体能够定义的还额外能够定义函数。并且这些变量和函数还能拥有访问权限。有了访问权限,这些东西在类体中就不会那么无法无天了?

可以这么形容:一个正常的人-->(类),拥有了-->(成员变量[属性])眼睛,鼻子,嘴巴, 手,腿;用这些属性-->l来构成动作(成员函数[方法])眼看, 耳听, 嘴说,手动, 腿走。他们各自负责自己的事情,不能说用手来走路, 腿来做事,这样岂不是乱套了。

所以面向对象编程,我学到这儿产生了些奇思妙想,,,你不能想这件事我需要哪些工具去完成,怎么完成。而是想,我完成的这件事属于什么类,并找到它天生就会什么?没有就创造。就比如说C要完成一个数组的赋值行为,打印输出行为。你很快就想到了数组我不能一步到头直接给他赋值,而是要一个个的赋值,一个个的访问。不到30秒,好了这件事我完成了。而面向对象编程,我不这么做!!我先想数组这东西是什么?一组数据;一组什么数据?一组有数字或字符就构成的数据组,他们就像军人战军姿那样,无缝连接,还要由自己报号。再想象一下,还有没有由什么东西派生出数组的,好像没有。好了,数组就是一个祖先类了(姑且认为你绝无仅有),首先你有哪些特征(属性)?

数组大小、数组类型,还有吗? 暂时没想到,,,再想想,这些东西是当前数组具备的吗?没错是的!我暂时就认你这个东西(类)了,以后再遇到别的,再说!开始定义类:

#include <iostream>
using namespace std;

class array{
private://下面的东西是我独有的
    static int m_size;//我有大小,就跟人类有黑色的头发一样
    int *num;//我不知道我今年多大了,你来告诉我

//我也叫数组,我有类型是int型 你就发现我叫int型 但是我不告诉你还有一个跟我同类的数组是char型的

public://我可以为您做什么呢? 
    void setData(int i, int val)//你可以让我赋值吗?可以的。
    {
        *(num + i) = val;
    }
    int getData(int i)//你可以让我看看你里面有什么吗?(怪怪的...)
    {
        return *(num + i);
    }
    int getlength(void)//你可以让我看看你的长度吗?可以的
    {
        return m_size;
    }
    array()//悄悄地构造
    {
        num = new int[m_size];
    }
    array(int size)//悄悄地重载
    {
        m_size = size;
        num = new int[m_size];
    }
    array(const array &obj)//悄悄地拷贝构造
    {
        m_size = obj.m_size;
        num = new int[m_size];
        memcpy(num, obj.num, sizeof(int) * m_size);
    }
    ~array()//悄悄地析构
    {
        delete[] num;
    }

};


int array::m_size = 10;//初始化静态变量

恩,一看这么长,我明明用C可以3,4行解决的,干嘛把事情弄的那么复杂讷。

那是因为我还没有尝到类带给我们的甜头。暂时就这些,学习路上也得一步一个脚印的。

以上就是一个类的定义,想必我是让自己的记忆更深刻了。。好了闲言少叙吧!


上面的所有函数都是在类体中定义的,C中函数有申明,有定义。C++怎么能放弃这么规矩的东西呢。所以类型内声明,类体外定义C++是允许的。

只不过要想类体内的函数在类体外实现,还得加点东西:

语法:<返回类型> <类名> :: <函数名>(入参1, 入参2, ...){...;;;}

前面所介绍的内联函数,也能当作内体类的成员,也能放类外修饰后定义,类内尽量不要用inline修饰函数, 修饰了虽合法,但毫无作用

上面的类定义使得,后续的访问井井有条,什么该做,什么不该做,什么会做,什么不会做,不会做的我也不能强加于类, 我会做的我会帮你处理好的,怎么处理的你无须知晓。有了访问权限,久之这变成了类的一大属性之一---封装

二、如何创建对象

有了Array类之后我们就能创建对象了,回想以下怎么创建结构体变量的。---- struct student stu; 就可以了;如何创建结构体指针?----struct student *pstu;//这个指针指向这个结构体。

关于结构体和类的区别:

                              作用域

特征

C结构体

C++结构体

C++类

基本数据类型(成员)(成员属性)

 

基本/高级指针成员

高级数据类型(struct union eumn)

(成员)函数(方法)

×

成员(数据)权限

×

√ 默认public

√ 默认private

构造函数

×

×

析构函数

×

×

同理,

创建对象:Array arr;//在栈上创建对象。

创建对象指针: Array *parr;

创建对象时class关键字可以省略,不省略,例如:class Array *parr  = new Array;//在堆上创建类,同样真确。创建多个类时,类名不能重复。

除了创建单个对象或对象指针,还可以创建对象数组:Array morearr[10] =  {3, 4};//创建时要初始化两者之间互为充分必要条件

如何访问成员

arr.length();
arr.setData(1, 10);
arr.getData(2);

parr->length();
parr->setData(1, 10);
parr->getData(2);

访问成员时受访问权限的影响。

在类内:无论函数被声明为public 、private、protected都是可以相互访问的。

在类外:只能通过对象访问成员,并且通过对象能访问的只能时public成员不能在类外(定义类的代码之外)访问private和protected成员。

比较复杂的是在继承中的使用,则就又别有洞天了,在后面我将会慢慢整理。

栈内存是程序自动管理的,不能使用delete删除在栈上创建的对象。堆内存有程序员管理,对象使用完毕后可以通过delete删除。实际应用中new和delete往往成对出现,且一般类内有指针变量时,析构函数最终是要进行释放的。以防造成内存泄漏。虽然一般程序中无视垃圾内存值影响不大,养成delete掉不再使用的对象是一种良好的习惯

声明private的成员和声明为public的成员的次序任意,既可以先出现private部分,也可以先出现public部分。如果什么都不写,那么类中的所有成员默认为private.

C++内存对象模型

利用sizeof()运算符来看看一个对象到底占用多大的内存空间,测试代码如下:

#include <iostream>
using namespace std;

class base{
private:
    int m_a;
    char *m_name;
    float m_high;
protected:
    int m_b;
public:
    int m_c;
    base():m_a(1), m_high(172.3), m_name("jobs"), m_b(2), m_c(3)
    {
	cout<<"Default constructor was called"<<endl;
    }
    base(int a, int b, int c, char *name)
    {
	cout<<"Costum constructor was called"<<endl;
	m_a = a;
	m_b = b;
	m_c = c;
	strcpy(m_name, name);
    }
    ~base(){cout<<"Destructor was called"<<endl;}
    void show();

};

void base::show()
{
    cout<<"private a = "<<m_a<<endl;
    cout<<"prrotected b = "<<m_b<<endl;
    cout<<"public c = "<<m_c<<endl;
}

int main()
{
    base obj;
    cout<<"stack obj size is "<<sizeof(obj)<<endl;

    base *pobj = new base;
    cout<<"heap obj size is "<<sizeof(*pobj)<<endl;

    cout<<"class size is "<<sizeof(base)<<endl;

    delete pobj;
    return 0;
}

我们来预测以下他的大小是多少?

首先,类本身不占用内存空间;当且仅当创建对象的时候调用构造函数后确定了实际内存空间的大小:

那么确定的是3个int类型占用3 * 4 = 12 个字节,float对于32位编译器可能也占用4个字节。指针变量也占用4个字节所以一共是4* 5 = 20个字节。那么成员函数占不占用内存空间呢?来测试一下。

由此可以判断,推测没错。对象的大小只受成员变量的影响,和成员函数没有关系。

如果show()被定义为内联函数呢?又会怎么样?

#include <iostream>
using namespace std;

class base{
private:
    int m_a;
    char *m_name;
    float m_high;
protected:
    int m_b;
public:
    int m_c;
    base():m_a(1), m_high(172.3), m_name("jobs"), m_b(2), m_c(3)
    {
	cout<<"Default constructor was called"<<endl;
    }
    base(int a, int b, int c, char *name)
    {
	cout<<"Costum constructor was called"<<endl;
	m_a = a;
	m_b = b;
	m_c = c;
	strcpy(m_name, name);
    }
    ~base(){cout<<"Destructor was called"<<endl;}
    void show();

};

inline void base::show()
{
    cout<<"private a = "<<m_a<<endl;
    cout<<"prrotected b = "<<m_b<<endl;
    cout<<"public c = "<<m_c<<endl;
}

int main()
{
    base obj;
    cout<<"stack obj size is "<<sizeof(obj)<<endl;

    base *pobj = new base;
    cout<<"heap obj size is "<<sizeof(*pobj)<<endl;

    cout<<"class size is "<<sizeof(base)<<endl;

    delete pobj;
    return 0;
}

运行结果仍然是一样的:

 但是文件大小有所不同:

未用Inline修饰:

用了inline修饰后:

这就说明了,inline之后属于代码拷贝到调用处,原先的函数定义就移除了,后面无法间接调用。(不过这里我还是有很多疑问的,为什么加了inline后,可执行程序的体积怎么减小了。。)

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值