C++与C语言的重要区别之一就是,C语言是面向过程编程,C++是面向对象编程,C++中加入了类和对象,因此C++很多情况下更加适合开发大型项目。本篇博客将简单介绍面向对象编程的思想,梳理C++中类和对象的相关基础语法。
面向过程与面向对象
我的个人理解是:面向过程关注的是做某一件事情的具体过程,就是把做某件事的过程拆成一个个步骤,然后按照顺序来执行每一个步骤,执行完所有步骤之后就完成了这件事情;面向对象关注的是某件事情中涉及到的对象以及对象之间的交互,就是分析某件事情是由哪几类对象构成,然后考虑这些对象使用哪些方法来解决这件事情。 面向过程与面向对象具体的特点和优缺点,这篇博客中不详细介绍。
类和对象
struct在C++中的变化
C++是兼容C语言语法的,因此C++中也有struct 关键字。在C语言中的struct是用来标识结构体类型的关键字,到了C++中,struct有了新的变化,struct结构体得到了扩充。C语言里面struct中只能定义变量,而C++struct中可以定义变量和函数。
struct Student
{
char _name[10];
int _age;
int _id;
void Init(const char* name, int age, int id)
{
strcpy(_name, name);
_age = age;
_id = id;
}
void Print()
{
cout << _name << endl;
cout << _age << endl;
cout << _id << endl;
}
};
int main()
{
struct Student s1;
Student s2;
s1.Init("zhangsan", 18, 202108101);
s1.Print();
return 0;
}
C++兼容C里面结构体的用法,同时struct在C++中也升级成了类。
类的定义
class classname
{
};
class 为定义类的关键字,ClassName 为类的名字,{} 中为类的主体,注意类定义结束时后面分号不能省略。 类体中内容称为类的成员:类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。
类的两种定义方式:
- 声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
- 类声明放在.h文件中,成员函数定义放在.cpp文件中,注意:成员函数名前需要加类名
::
一般来说使用方式2会更好。
类访问限定符
C++的优点之一就是封装,封装就是:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
封装是一种更好的严格管理
- 数据和方法都封装到类里面
- 可以给你访问的定义成共有,不想给你访问的定义成私有
具体的实现方式就是用类访问限定符来修饰成员变量和方法,控制访问权限。
类访问限定符:
- public(公有)
- protect(保护)
- private(私有)
访问限定符说明
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
- 如果后面没有访问限定符,作用域就到 } 即类结束。
- class的默认访问权限为private,struct默认为为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
class Student
{
private:
char _name[10];
int _age;
int _id;
public:
void Init(const char* name, int age, int id)
{
strcpy(_name, name);
_age = age;
_id = id;
}
void Print()
{
cout << _name << endl;
cout << _age << endl;
cout << _id << endl;
}
};
int main()
{
struct Student s1;
Student s2;
s1.Init("zhangsan", 18, 202108101);
s1.Print();
return 0;
}
类的作用域
类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用:: 作用域操作符指明成员属于哪个类域。
原因:不同类可能会有重名的变量
class Person
{
public:
void PrintPersonInfo();
private:
char _name[20];
char _gender[3];
int _age;
};
void Person::PrintPersonInfo()
{
cout << _name << " "<< _gender << " " << _age << endl;
}
类对象的大小
对于类的不同对象,他们的成员变量的值是各不相同的,但是成员函数都是一样的,所以每个类对象只需要存储成员变量,将成员函数存在公共代码区,用到的时候调用即可。 类对象的存储结构如下: 结论:计算类或者类对象大小(类的大小就是类对象的大小),只看成员变量,考虑内存对齐,C++内存对齐规则和C结构体一致。
class A1
{
public:
int _a;
public:
void func() {}
};
class A2
{
public:
void func() {}
};
class A3
{
};
int main()
{
cout << sizeof(A1) << endl;
cout << sizeof(A2) << endl;
cout << sizeof(A3) << endl;
return 0;
}
对象实例化
用类类型创建对象的过程,称为类的实例化
- 类是对对象进行描述的,类似于一个模型,描述了类有哪些成员,当我们定义出一个类时并没有分配实际的内存空间来存储它;
- 一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量Person类是没有空间的,只有Person类实例化出的对象才有具体的年龄。
- 举例来说,类就像一个建筑的设计图,描述了建筑的样式,建筑实际上并不存在,而实例化出的对象就是照着设计图建造出来的实体建筑,是实际存在的。
this指针
Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢? C++中通过引入this指针解决该问题,即:C++编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量”的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。
class Date
{
public:
void Init(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print()
{
cout << _year << "-" << _month << "-" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
d1.Init(2022, 9, 23);
d1.Print();
Date d2;
d2.Init(2022, 9, 27);
d2.Print();
return 0;
}
this指针存在哪? this指针是临时变量,所以存在栈帧里面,有些编译器会放到寄存器中。VS会将它放到ecx寄存器中。
this指针可以为空吗? 是可以的,语法不一定会错,但是逻辑上很可能会有问题。
class A
{
public:
void show()
{
cout << "show()" << endl;
}
private:
int _a;
};
class B
{
public:
void Print()
{
cout << _a << endl;
}
private:
int _a;
};
int main()
{
A* p1 = nullptr;
p1->show();
B* p2 = nullptr;
p2->Print();
return 0;
}
|