类与对象入门
这是什么:类(class) = 把数据和行为打包在一起的自定义类型,用它造出来的具体东西叫对象。
为什么用:变量存数据、函数做事情,各管各的。类(class)把它们打包在一起:数据(成员变量)和行为(成员方法)住进同一个"模具"。数据散着放容易乱套,捆在一起既好读又好用。
如何用:先造一只最小的 Dog,看构造函数怎么给对象"出生登记",再用 public/private 把数据关进抽屉里。
一只最小的 Dog 类
#include <iostream>
#include <string>
using namespace std; // 从这章起省略 std:: 前缀,代码更清爽
class Dog {
public:
// 构造函数:造对象时自动执行,负责"出生登记"
Dog(string name, int age) {
this->name = name; // this->name = 自己的成员,区别于参数 name
this->age = age;
}
// 成员方法:这个类"会做的事"
void introduce() {
cout << "我叫" << name << ",今年" << age << "岁,汪!" << endl;
}
// 新增:叫一声
void bark() {
cout << name << ":汪汪汪!" << endl;
}
private:
string name; // 私有成员:外面不许直接碰
int age;
};
int main() {
Dog d("旺财", 3); // 用类造一个对象
d.introduce(); // 对象干活
d.bark(); // 汪汪汪!
return 0;
}
你会看到
我叫旺财,今年3岁,汪!
旺财:汪汪汪!
逐块解读
| 代码 | 作用 |
|---|---|
class Dog { ... }; |
定义类,结尾的分号不能少(新手高频报错点!) |
public: |
公开区:外界可以直接访问 |
private: |
私有区:只许类自己的方法碰,保护数据 |
Dog(string name, int age) |
构造函数:与类同名、不写返回类型,造对象时自动调用 |
this->name |
"这个对象自己的 name",用来和参数 name 区分 |
Dog d("旺财", 3); |
造对象:按模具"出生"一只叫旺财、3 岁的狗 |
d.introduce(); |
用 . 调用对象的成员方法(和 Python 的 d.introduce() 眼熟吧) |
d.bark(); |
调用新增的叫方法 |
为什么要分 public / private
把 name、age 藏进 private,外界就无法直接乱改——想了解或修改这只狗,只能走 introduce()、bark() 这类公开方法的"正规渠道"。这就是封装:细节藏起来,只留好用的接口。
对比 Python:Python 的"私有"只是约定(
_name写法),大家默认不动它;C++ 是编译器强制执行——这就是编译型语言的较真。
更多:多个对象共存
类就像模具,可以造出很多独立的对象,彼此互不干扰:
int main() {
Dog d1("旺财", 3);
Dog d2("小黑", 5);
d1.introduce(); // 我叫旺财,今年3岁,汪!
d2.introduce(); // 我叫小黑,今年5岁,汪!
d1.bark(); // 旺财:汪汪汪!
d2.bark(); // 小黑:汪汪汪!
return 0;
}
每个对象有自己的 name 和 age,this-> 指向当前正在操作的那个对象本尊。
❓ 常见问题
Q1:类结尾为什么要加分号?
class Dog { ... }; // ← 这里的分号
原因:C++ 把类定义当成一种"类型声明",和变量声明一样需要分号结束。漏了分号,编译器会在下一行报错,提示你"缺少分号"。
Q2:this-> 必须写吗?
不一定。在成员方法里直接写 name 也能访问到成员变量。但写 this->name 能明确区分"成员变量"和"同名参数/局部变量",避免歧义,是好习惯。
Q3:构造函数为什么没有返回类型?
构造函数是特殊函数,名字必须和类一样,不写返回类型(连 void 都不写),因为它不"返回"任何东西,它的工作是"把对象初始化好"。
⚠️ 新手翻车现场
翻车一:在 main 里直接改 private 成员
// 错误:编译器直接拒绝
d.age = 100;
问题:age 是 private,外界不许直接碰。
修正:如果需要外部读取或修改,加一个公开方法,比如 void setAge(int a) { age = a; },通过方法"正规渠道"操作。
翻车二:忘了类结尾的分号
class Dog {
// ...
} // ← 漏了分号
int main() { ... } // ← 这里报错,说找不到类型
问题:编译器以为类定义还没结束,把后面的 main 当成了类的一部分。
修正:补上 };。
🎯 什么时候用类
- 一组数据和一组操作天然绑定(如"狗"有名字年龄,会自我介绍)
- 需要创建多个拥有相同结构但数据不同的对象
- 想保护内部数据不被外界随意篡改(封装)
📝 本章小结
- 类是模具,对象是产品;
public对外营业,private谢绝参观 - 构造函数与类同名、无返回类型,造对象时自动调用
this->指向当前对象本尊,用来和参数区分- 类结尾的分号不能少
- 记忆口诀:类是模具,对象是产品;public 对外营业,private 谢绝参观;类结尾的分号别忘写。
动手改
- 给
Dog加一个int getAge()方法,返回年龄,在main里打印 - 在
main里再造一只Dog d2("小黑", 5);,让两只狗轮流自我介绍 - 试试在
main里写d.age = 100;——编译器会直接拒绝,亲眼看看 private 的威力
下一章:综合练习,把前七章的知识全串起来 🐸