cpp学习笔记1--class

发布于:2025-05-07 ⋅ 阅读:(12) ⋅ 点赞:(0)

2年前学过cpp,但是一直没有用到,现在要读研了,终于要用到了,重新拿出来看一看,觉得很多东西都能在c和python上看到影子。

#include "iostream"
class Person {
private:
    std::string name;
    int age;

public:
    // 默认构造函数
    Person() : name("Unknown"), age(0) { std::cout << "init 1" << std::endl; }

    // 带参数的构造函数
    Person(const std::string& n, int a) : name(n), age(a) { std::cout << "init 2" << std::endl; }

    // 拷贝构造函数
    Person(const Person& other) : name(other.name), age(other.age) { std::cout << "init 3" << std::endl; }

    // 析构函数
    ~Person() {
        std::cout << name << "对象被销毁" << std::endl;
    }

    void introduce() {
        std::cout << "我叫" << name << ",今年" << age << "岁。" << std::endl;
    }
    void change(std::string new_name,int new_age) {
        name = new_name;
        age=new_age;
        std::cout << "changing is over" << std::endl;
    }
};

我来逐行解析一下。

首先私有变量是只有此类的此实例对象的公开区域的函数能调用的(后面还会有其他区域也能调用),也就是Person p1;Person p2;p2的pubilc函数不能调用p1的age,但是可以调用自己的,外部程序也无法直接访问age

Person p1;
Person p2;
p1.introduce();
p2.introduce();
p2.change("Trump", 72);//p2可以改变自己的age
p2.introduce();
p2.age=10;//错误用法
 

然后public的第一个构造函数。它相当于python里的self.init,是用来初始化私有变量的,name("unknown")就是给name赋值"unknown"。第一个初始化初始的是默认值,不需要传入参数,也不需要括号。而public的第二个带参数的构造函数就需要了,两者都只能初始化一次。

Person p1;
int x = 13;
std::string name = "Mike";
Person p2(name, x);
p2("x", 1);//常量、变量都可以,但不可重复初始化

我定义的这个name是string型,在构造函数里应该就是const std::string& n=name,这在c里是不合法的,因为n和name的类型不同,但在cpp里这表示拷贝,那n和name地址是否一样呢?验证一下

Person(const std::string& n, int a) : name(n), age(a) { std::cout << "init 2 "<<&n <<" " << &name << std::endl; }

int x = 13;
std::string name = "Mike";
std::cout << &name << std::endl;
Person p1(name, x);

输出结果:

000000D8230FFA70
init 2 000000D8230FFA70 000000D8230FFA90

说明Person之前的name和Person里的n是同地址的,而Person里的n和name是不同的,这是因为第一个name是在main里定义的,第二个name是Person的一个private变量,改成std::string xname = "Mike";就好理解了。

接下来的拷贝构造函数是什么呢?如下图,很明显,它也是一个拷贝,那么&p3==&p4?当然不是。Person(const Person& other),&p3==&other是成立的,而p4是一个新创建的Person,所以地址不同,Person p4=p3,也是可以直接调用这个拷贝函数的。

int x = 13;
std::string name = "Mike";
Person p3(name, x);
Person p4(p3);
std::cout << "p3 address " << &p3 << std::endl;
std::cout << "p4 address " << &p4 << std::endl;

既然p3,p4地址都不同,那么拷贝之后再变化p3,p4也是不会跟着变化的。

同理我们可以直接如下使用拷贝,显然,p2=p1会调用之前构造的拷贝函数,但是&p3=p2不会,最后&p3==&p2,但不等于&p1

Person p1;
Person p2=p1;
Person &p3 = p2;
Person &p3 = &p2;//不符合拷贝用法,不能传入地址
std::cout << "p1 address " << &p1 << std::endl;
std::cout << "p2 address " << &p2 << std::endl;
std::cout << "p3 address " << &p3 << std::endl;

还有需要注意的是,初始化之后再改变x,p2的age也不会变。

int x = 13;
std::string name = "Mike";
Person p2(name, x);
p2.introduce();
x++;
p2.introduce();

最后是析构函数,是在Person的生命周期结束时自动调用的,也可以手动调用,会释放内存。它们是在栈区的,以p1,p2,p3创建 ,就会以p3,p2,p1自动释放。

Person p1;
Person p2=p1;
Person &p3 = p2;
std::cout << "p1 address " << &p1 << std::endl;
std::cout << "p2 address " << &p2 << std::endl;
std::cout << "p3 address " << &p3 << std::endl;
//p1.~Person();
p2.introduce();
p3.introduce();
p2.change("mike", 23);
p2.introduce();
p3.introduce();

而这个的p3和p2只会释放一次


网站公告

今日签到

点亮在社区的每一天
去签到