C++ 学习笔记04
一、匿名对象
作用
赋值,初始化,传参数
用法
类型(构造函数的参数列表)
注意: 匿名对象的生命周期非常的短(临时的值)
匿名对象不是一个必要的语法,它能让我们的代码变的更加简洁。
示例1
#include <iostream>
using namespace std;
class Person
{
private:
int age;
int score;
public:
Person(int a, int s):
age(a),
score(s) { }
void show()
{
cout<<age<<" "<<score<<endl;
}
};
void fun(Person p)
{
p.show();
}
int main()
{
fun(Person(18, 100));//创建匿名对象作为函数的参数,省去了额外创建一个对象的步骤,代码简洁了!
//这是不使用匿名对象的情况
Person p(18, 100);
fun(p);
return 0;
}
匿名对象初始化数组
Person ps[5] = {Person(1), Person(2), Person(3), Person(4), Person(5)};
for(int i = 0;i < 5;i++)
{
ps[i].show();
}
二、this指针
作用
类的每个成员函数中都有一个指针叫this,指向调用成员函数的那个对象。
- 是一个指针,指向对象本身,
- this只能在类的内部使用,在类的内部调用成员都是使用this调用的,可以省略
示例2
#include <iostream>
using namespace std;
class Person
{
private:
int age;
public:
Person(int age)
{
this->age = age;//this->age 是指向当前构造函数的对象的age
}
void show()
{
cout<<this->age<<endl;//就算这里不写this,系统也会给我们补上this,在成员函数中调用成员都是通过this指针调用的。不写this属于隐式调用this
}
};
int main()
{
Person p(1);//创建对象p,所以这里执行构造函数时,构造函数的this指向p
p.show();//show中this指向p,因为p调用show
}
this的一般用法
在类的内部,将当前对象当做参数进行传递
练习1
Person类,包含私有属性:姓名name,性别bool gender,年龄age,另一个对象的指针 Person * lover;
- 构造函数初始化成员变量 name gender
- 成员函数setAge给年龄赋值
- 成员函数marry(Person& other) 输出name"和"other.name"喜结良缘!";
- 成员函数show(); 输出"大家好!我是"gender,name,今年"age; 输出"爱人是:"lover->name;
private类:
string name;
bool gender;
int age;
Person * lover; 手指头
查看练习代码
#include <iostream>
#include <string>
using namespace std;
class Person
{
private:
string name;
bool gender;
int age;
Person* lover;
public:
//在初始化列表中成员变量和形参列表重名,不会歧义。因为初始化列表中只能对成成员变量初始化。
//()中的值,优先从形参列表开始找。
Person(string name, bool gender):name(name),gender(gender)
{
}
void setAge(int age)
{
this->age = age;
}
void marry(Person& other)//other是Person类型的引用,会指向实参对象,实参就是结婚的另一半
{
lover = &other;//main函数中,xiaoming调用marry,所以;lover是xiaoming的成员,other是小强对象
other.lover = this;//main函数中,xiaoming调用marry,所以this指向xiaoming对象,所以这里是xiaoqiang的lover指向了xiaoming
cout<<name<<" "<<other.name<<"喜结良缘"<<endl;
}
void show()
{
cout<<"大家好 我是"<<name<<" "<<(gender?"男":"女")<<" 今年"<<age<<endl;
cout<<"我的爱人是 "<<lover->name<<endl;
}
};
int main()
{
Person xiaoming("小明", true);
Person xiaoqiang("小强", false);
xiaoming.setAge(18);
xiaoqiang.setAge(81);
xiaoming.marry(xiaoqiang);
xiaoming.show();
xiaoqiang.show();
return 0;
}
三、拷贝构造函数
思考:下面代码输出几次 “student”
class Student
{
public:
Student()
{
cout<<"student"<<endl;
}
private:
string m_name;
};
int main()
{
Student stu1;//创建对象调用构造函数
Student stu2 = stu1;//使用同类型一个对象初始化另一个对象,这就是复制对象,会调用拷贝构造函数
Student stu3(stu1);//使用同类型一个对象初始化另一个对象,这就是复制对象,会调用拷贝构造函数
}
1.声明:
函数名(类名)(const 类名 &对象名)
使用一个对象初始化另一个对象的时候调用拷贝构造
拷贝构造函数的参数列表必须是 const 类名 &对象名。
示例3:
#include <iostream>
using namespace std;
class Person
{
private:
int age;
public:
Person(int age)
{
this->age = age;
}
//根据参数列表判断这是拷贝构造函数,Person类型的拷贝构造函数,参数必须是Perosn类型
Person(const Person& other)
{
cout<<"拷贝构造"<<endl;
}
void show()
{
cout<<this->age<<endl;
}
};
int main()
{
Person a(19);
cout<<"start"<<endl;
Person b(a);//调用对象b 的拷贝构造函数
Person c = a;
cout<<"end"<<endl;
b.show();
}
2.默认拷贝构造函数
默认拷贝构造函数:
- 在没有显式的定义拷贝构造函数时,系统会自动生成一个拷贝构造函数,
功能: 将成员变量逐个赋值(浅拷贝) - 如果显式的定义拷贝构造函数,那么默认拷贝构造函数和默认构造函数都没有了
示例4:
#include <iostream>
using namespace std;
class Person
{
private:
int age;
public:
Person(int age):age(age)
{
}
//Person类中没有显式的定义拷贝构造函数
int getAge()
{
return age;
}
};
int main()
{
Person* p = new Person(19);//在堆空间创建一个对象
Person* p2 = new Person(*p);//*p是一个Person对象,这里是使用同类型的一个对象初始化另一个对象,调用拷贝构造函数,但是在Person中没有显式的定义拷贝构造函数,所以这里调用默认拷贝构造函数
cout<<p->getAge()<<endl;,
cout<<p2->getAge()<<endl;
}
总结:
- 如果没有自定义的拷贝构造函数则系统自动生成一个默认的拷贝构造函数
- 当采用直接初始化或复制初始化实例化对象时,系统自动调用拷贝构造函数
- 系统默认拷贝构造函数的功能:逐个对成员变量进行赋值
- 显示的定义了拷贝构造函数,系统默认的就不存在了,函数的功能(对变量进行的赋值),就由我们自己来完成了