目录
一、类的引入和定义
1.1面向过程和面向对象初步认识:
1.语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。 2.C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完 成。
1.2类的引入
C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。
#include<assert.h>
#include<string.h>
struct Book
{
void init(int book_id, const char* bookname){
assert(bookname);
_book_id = book_id;
strcpy(_bookname, bookname);
}
void print() {
cout << _book_id << " " << _bookname << endl;
}
int _book_id;//为了区分函数中的形参,一般加上—命名
char _bookname[25];
};
int main()
{
Book b1;
b1.init(123, "三国演义");
b1.print();
return 0;
}
上面结构体的定义,在C++中更喜欢用class来代替。
1.3类的定义
class className
{
//数据成员
//成员函数
}; // 一定要注意后面的分号
1.class为定义类的关键字,ClassName为类的名字,{}中为类的主体,注意类定义结束时后面分 号不能省略。2.类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。
类的两种定义方式:
1. 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
class person
{//声明和定义都放在类中
private:
char* _name;
char* sex;
int _age;
public:
void print(){
cout<<_name<<" "<<sex<<" "<<age<<endl;
}
};
2. 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名::
//person.h
class person
{//声明放在类的person.h中
private:
char* _name;
char* sex;
int _age;
public:
void print();
};
//定义放在person.cpp中
//person.cpp
#include"person.h"
void person::print()
{
cout<<_name<<" "<<sex<<" "<<age<<endl;
}
二.类的访问限定符及封装
2.1访问限定符
C++ 通过 public、protected、private 三个关键字来控制成员变量和成员函数的访问权限(也称为可见性),分别表示:公有的、受保护的、私有的。
class Base {
public:
// 公有成员
protected:
// 受保护成员
private:
// 私有成员
}
1. public修饰的成员在类外可以直接被访问 2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的) 3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止 4. 如果后面没有访问限定符,作用域就到 } 即类结束。 5. class的默认访问权限为private,struct为public(因为struct要兼容C)
2.2封装
封装是C++面向对象三大特性之一 (封装、继承、多态)
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来 和对象进行交互。封装本质上是一种管理,让用户更方便使用类。(比如:当我们使用手机时,我们与其交互的方式也是一个很好的例子。手机作为一个复杂的设备,内部包含诸如处理器、内存、摄像头、传感器等各种硬件元件。然而,对于用户而言,与手机进行交互的只是一些表面上的功能和界面。)这就是封装的思想,它提高了对用户的友好性。
在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来 隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。
2.3类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
class Person
{
public:
void PrintPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
cout << _name << " "<< _gender << " " << _age << endl;
}
三、类对象模型与this指针
3.1类的实例化
用类类型创建对象的过程,称为类的实例化
1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没 有分配实际的内存空间来存储它;2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
int main()
{
Person._age = 100; // 编译失败:error C2059: 语法错误:“.”
return 0;
}
Person类是没有空间的,只有Person类实例化出的对象才有具体的年龄。
3. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设 计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象 才能实际存储数据,占用物理空间。
class person
{
private:
char* _name;
char* _sex;
int _age;
public:
void show();
};
int main()
{
person p1;//类的实例化
p1._name="小明";
p1._sex="男";
p1._age=19;
p1.show();
return 0;
}
3.2类实例内存模型
举一个例子验证:
可以看到print函数call的指定访问的函数地址是一样的,因此可以说明类成员函数的代码段是独立放在内存中的。
3.3this指针
3.3.1this指针的引出
clclass Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
//编译时:
/*void Init(Date* const this,int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}*/
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
//编译时:
/*void Print(Date* const this)
{
cout <<this->_year << "-" <<this->_month << "-" <<this->_day << endl;
}*/
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
Date d1, d2;
d1.Init(2022, 1, 11);
d2.Init(2022, 1, 12);
d1.Print();
d2.Print();
//编译时
//d1.Init(&d1,2022,1,11);
//d2.Init(&d2,2022,1,11);
//d1.Print(&d1);
//d2.Print(&d2);
return 0;
}
对于上述类,有这样的一个问题:
Date类中有 Init与Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏 的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
3.3.2 this指针的特性
1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值.2. 只能在“成员函数”的内部使用 3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给 this形参。所以对象中不存储this指针 4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递 。