c++类的定义与使用

  • c++的面向对象和面向过程
  • 从struct到class的引入
  • class的定义以及使用

一.c++的面向对象和面向过程

c语言是一门结构化,面向过程的语言,而c++可以支持c。所以c++并不是一门单纯的基于面向对象的语言,C++既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计。

  • 面向过程:关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题
  • 面向对象:关注的是对象,也就是将一个问题分为多个对象之间的交互来解决。

面向对象的三大特性:封装,继承,多态。

  • 封装:将数据和方法结合到一起,隐藏对象的属性和实现细节,选择性的提供一些接口来和对象进行交互。封装的本质是一种管理,可以让用户更方便的使用类
  • 继承: 可以利用已有的数据类型来定义新的数据类型。所定义的新的数据类型不仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。
  • 多态: 使用多态能够使得不同的对象去完成同一件事时,产生不同的动作和结果。

二.从struct到class的引入

c语言中struct:

  • struct只能定义变量,不能定义函数
  • 在创建对象时,必须加入struct关键字

c++中struct:

  • struct中既可以定义变量,也可以定义函数
  • 在创建对象时,不需要加入struct关键字,即:只有结构体名就可以代表类型
#include
using namespace std;
//结构体节点的定义
struct Node
{
	//不用加struct
	Node* next;
	int data;

	void PushBack(Node* phead, int x)
	{
        //....
    }
	
}

int main()
{
    //无需加struct就可以定义变量
    Node* head = NULL;
    return 0;
}
2.1struct 和 class的区别
  • struct 的成员默认访问权限为public,class的成员默认访问权限为private
  • c++要兼容c,所以在c++中,struct可以当结构体使用,也可以定义类。

总结:

  • 虽然struct和class都可以定义类,但是在c++中喜欢用class

三.class的定义以及使用

class className
{
	//成员变量和成员函数
};
  • className 为类名,class为关键字,{}里面的是类体,最后;不能丢
  • 类中定义的变量叫做成员变量或者类的属性,函数叫做成员函数或者成员方法,
  • 对于成员函数可以在类中定义,也可以在类中声明,类外定义。在类外定义时需要加类名::,表示该函数属于类域
3.1类的访问限定符

c++将成员变量和成员函数封装到类中,通过访问限定符来规定成员的访问权限,提供哪些接口给外部用户。类的访问限定符有三种:public(公有),protected(保护),private(私有)

  • public修饰的成员可以在类外访问
  • private和protected修饰的成员在类外不能直接被访问
  • 访问限定符的作用范围:从一个限定符到另一个限定符
  • struct的默认访问限定符为public,class为private
3.2类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。

#include
using namespace std;
class Data
{
public:
	void Show();
private:
	int _year;
	int _month;
	int _day;
};

void Data::show()
{
    cout << _year << endl;
    cout << _month << endl;
    cout << _day << endl;
}
3.3类对象的创建-类的实例化

将类比作一个建筑图纸,那么对象就是建筑物。定义出一个类并没有分配实际的内存空间来存储它,实例化为对象后才开辟空间。

  • 一个类可以实例化多个对象,对象空间中只存储成员变量。因为每个成员变量都是不一样的,但是每个对象的成员函数都是一样的,所以只需要一份共享的成员函数即可,保存在代码段。
#include
using namespace std;
class Data
{
public:
	void Show();
private:
	int _year;
	int _month;
	int _day;
};

void Data::Show()
{
    cout << _year << endl;
    cout << _month << endl;
    cout << _day << endl;
}
int main()
{
    Data d1;
    Data d2;
    
    return 0;
}
3.4类对象的大小

类对象的大小只包含成员变量所占用的空间,代码共用一份即可。其中类对象的成员也需要满足内存对齐。
结构体内存对齐的规则:

  1. 第一个成员在偏移量为0的地址处
  2. 其他成员都要对齐到对齐数的整数倍地址处(对齐数:默认对齐数与成员的最小值)
  3. 结构体总大小:最大对齐数的整数倍
  4. 如果嵌套了结构体的话,将该结构体对齐到该结构体中最大对齐数的整数倍
3.5this指针
#include
using namespace std;
class Data
{
public:
	void Show();
private:
	int _year;
	int _month;
	int _day;
};

void Data::Show()
{
    cout << _year << endl;
    cout << _month << endl;
    cout << _day << endl;
}
int main()
{
    Data d1;
    Data d2;

    d1.Show();
    d2.Show();
    
    return 0;
}
在上述代码中,由于成员函数只有一份,那么Show函数是怎么分辨出成员变量是属于哪个对象的呢?

在调用函数时,实际上编译器会将对象的地址当作参数传递给show函数,这个地址保存在this指针里面

  • 在函数定义处:实际上为void Data::Show(Data* this),有this指针这个隐含形参
  • 在调用处:实际上为d1.Show(&d1), d2.Show(&d2);

只是上述步骤,编译器来执行,不允许程序员显示使用,但是可以在成员函数内部使用this指针

this指针的特性:

  • this指针的类型:类类型*const this ,不允许改变this指针
  • this指针只能在成员函数内使用
  • this指针本质上是函数形参,存储在栈中
  • this指针是成员函数的第一个隐含形参,一般情况由编译器ecx自动传递,不需要用户使用
  • this指针可以为nullptr
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
     void Print()
     {
     cout << "Print()" << endl;
     }
private:
 	int _a;
};
int main()
{
     A* p = nullptr;
     p->Print();
    (*p).Print();
     return 0;
}


// 2.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{ 
public:
    void PrintA() 
   {
        cout<<_a<<endl;
   }
private:
 	int _a;
};

int main()
{
    A* p = nullptr;
    p->PrintA();
    (*p).PrintA();
    return 0;
}

在上述代码中,第一个案例是正确的,程序不会报错,第二个是错误的,因为访问了nullptr指针

看代码不能只看表象,需要看底层,编译器看待p->PrintA();

  1. 需要去调用PrintA这个函数,转换为汇编call语句
  2. 需要传递this指针参数,为nullptr

上面1,2案列在这两步并没有访问nullptr,但是第二个代码错误之处在于,访问了成员变量_a,而对象在nullptr处,所以编译器会报错,但是第一个代码并没有真正的访问nullptr,可以调用反汇编来观察

c++类的定义与使用_第1张图片

你可能感兴趣的:(c++,c++,开发语言)