说明
汇编、C面向过程,关注过程,分析出求解问题的步骤,通过函数调用逐步解决问题
C++、java等面向对象,关注对象,将一件事情拆分成不同对象,靠对象之间的交互完成
注:C++基于面向对象,即面向过程与面向对象混编,因为C++兼容C。而java纯面向对象
如:设计简单外卖系统:
面向过程:关注实现下单接单送餐等过程。在代码层面即方法/函数。
面向对象:关注实现类对象(用户骑手商家)之间的关系。在代码层面即类的设计及类之间的关系。
面向对象三大特性:封装、继承、多态
本文先只提封装。
封装:1.数据和方法都放在类中 2.访问限定符
封装是严格管理,不封装是自由管理,基本上是封装更好
类的作用域:
类定义了一个新的作用域,叫作类域,类的所有成员都在类的作用域中。
在类体外定义成员(如声明与定义分开时),需要使用::作用域解析符指明成员属于哪个类域。
类的实例化:用类类型创建对象的过程
类只是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。
一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。
访问限定符:public(公有),protected(保护),private(私有)
- public修饰的成员在类外可以直接被访问
- protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
- 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
若后面无访问限定符,默认到类结束 - class的默认访问权限为private,struct为public(因为struct要兼容C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
建议在定义类时明确访问限定符,不要用默认属性
实际项目开发中,成员变量以及只在类内部使用的成员函数(只被成员函数调用的成员函数)都建议声明为 private,而只将允许通过对象调用的成员函数声明为 public。
成员函数内联
成员函数若在类内定义,编译器可能会将其作为内联函数处理。
若不希望类内成员函数内联,则可在类内声明函数,在类外(类体后面)通过域限定符定义。
若希望成员函数定义在类外时内联,则在定义时加inline关键字。
const成员函数
将const修饰的类成员函数称之为const成员函数。
//声明
const int fun();//const修饰返回值类型,表示返回的值不可修改。
int fun() const;//const修饰成员函数,表示该函数只可读取而不可修改成员变量的值。
//定义
int fun() const{
return 0;
}
//const成员函数声明与定义都必须加const,因为带与不带const是两种不同的类型。
const修饰类成员函数,实际修饰的是该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改。
不需修改成员变量的成员函数推荐加const,以使得普通对象和const对象都可以调用,而需要修改成员变量的成员函数不能加,如日期类中+= ++ 等的实现。
类的大小
出于效率考量,类对象中只保存成员变量,成员函数存放在公共的代码段。
一个类或类对象的大小,实际就是该类中”成员变量”之和,也要进行内存对齐(对齐规则与C结构体一致)。
注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类。
代码
#include<iostream>
using namespace std;
//类
//定义类的两个关键字:struct/class
struct Student1 {
//C++兼容C里结构体的用法,同时struct在C++中也升级成了类
char name[10];
int age;
int id;
};
//C++类与C结构体不同的是除了可以定义变量,还可以定义方法/函数
struct Student2 {
//成员变量(类的属性)
char _name[10];
int _age;
int _id;
//↑加_是为防与成员方法中参数同名,具体区分方法是加_还是加m还是啥别的方式取决于公司规定
//成员函数(类的方法)
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;
}
};
class Student3 {//类名:Student3
//类体由成员变量与成员函数构成
//没有访问限定符修饰的就是默认的,class默认为private,struct为public
char _name[10];
int _age;
int _id;
public://到下一个访问限定符或当前类的结束为止,中间的部分成为public
void Init(const char* name, int age, int id) {
strcpy(_name, name);
_age = age;
_id = id;
}
private://到下一个访问限定符或当前类的结束为止,中间的部分成为private
void Print() {
cout << _name << endl;
cout << _age << endl;
cout << _id << endl;
}
};//依旧不能忘记最后的分号
class Person {
public:
void PrintPersonInfo();
//void PrintPersonInfo() const;
private:
char _name[20];
char _gender[3];
int _age;
};
// 这里需要指明PrintPersonInfo属于Person这个类域
void Person::PrintPersonInfo() {
cout << _name << " " << _gender << " " << _age << endl;
}
//void Person::PrintPersonInfo() const {
// cout << _name << " " << _gender << " " << _age << endl;
//}
//建议在定义类时明确访问限定符,不要用默认限定,以上例子仅为演示
int main() {
struct Student1 s1;//兼容C用法,struct Student1是类型
Student1 s2;//C++直接使用类名定义,对象定义在栈上。Student1是类名也是类型
//要在堆上定义对象则需要new以及配套的deleteg关键字,类似c的malloc与free。
strcpy(s1.name, "niokia");//*数组不能直接赋值
s1.id = 114514;
s1.age = 24;
strcpy(s2.name, "niokia0v0");//*数组不能直接赋值
s2.id = 1919810;
s2.age = 38;
//成员方法的使用
Student2 s3;//s3被称作对象
s3.Init("niokiaOVO", 12450, 16);
s3.Print();
Student3 s4;//该有名对象生命周期在当前函数
s4.Init("niokiaQAQ", 26650, 12);
//若在这里从外部访问private修饰的print,编译会报错
Student3();//匿名对象的生命周期只在当前行.
//匿名对象可用于在只需使用一次的场合简化"先定义有名对象再调用"的过程(以及单纯传参用)
//匿名对象可以用static修饰为静态的,但离开所在行后还是会销毁,static相当于不起作用
//更详细的有关内容可见于<<深度探索C++对象模型>>一书
//例:
//参考[日期类] http://t.csdn.cn/SWy8W
//先定义有名对象再调用之:
//Date today(2022,6,3);
//today.PrintWeekDay();
//匿名对象:
//Date(2022,6,3).PrintWeekDay();
//一般传参:
//Date d(2022,6,4);
//f(d);
//匿名对象传参:
//f(Date(2022,6,4));
//另:const引用可扩展匿名对象的生命周期到引用对象所在的域:
//const A& obj = A();
//此处相当于使得匿名对象有了obj这个名字
//必须是const引用,因为匿名对象具有常性
return 0;
}