🐸 青蛙编程网
首页 / C++ / C++ 基础 / 7. 类与对象

类与对象入门

这是什么:类(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 谢绝参观;类结尾的分号别忘写。

动手改

  1. 给 Dog 加一个 int getAge() 方法,返回年龄,在 main 里打印
  2. 在 main 里再造一只 Dog d2("小黑", 5);,让两只狗轮流自我介绍
  3. 试试在 main 里写 d.age = 100;——编译器会直接拒绝,亲眼看看 private 的威力

下一章:综合练习,把前七章的知识全串起来 🐸

📥 下载本章代码

ZIP 内含本章全部代码文件与说明,解压即用,与教程内容同步生成。