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只會釋放一次