Content:
- 构造函数和析构函数
- 构造函数的分类和调用
- 拷贝构造函数调用时机
- 构造函数调用规则
- 深拷贝和浅拷贝
- 初始化列表
- 类对象作为类成员
- 静态成员函数
- 成员变量和成员函数分开存储
- this用法
- 空指针访问成员变量
- const修饰成员变量
- 友元-全局变量做友元
- 普通函数做友元
- 友元成员变量
- 类做友元
1、构造函数和析构函数
#include<iostream>
using namespace std;
#include<string>
//构造函数和析构函数:完成对象初始化和清理工作,我们如果不提供构造和析构,编译器也会提供的,但是提供的是空实现
//构造函数:主要是创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用
//析构函数:主要用于对象销毁前系统自动调用,执行一些清理工作
class Person
{
public:
//构造函数
//1、无返回值也不用void
//2、函数名称和类名相同
//3、可以有参数,可以发生重载
//4、程序在调用对象时会自动调用构造,无需手动调用,只调用一次
Person()
{
cout<<"Person的构造函数"<<endl;
}
//析构函数
//1、无返回值,和void
//2、函数名和类名一样,在名称前加上符号~
//3、不可以有参数,不能重载
//4、 程序在对象销毁时会自动调用析构,无需手动调用,只调用一次
~Person()
{
cout<<"Person的析构函数"<<endl;
}
} ;
//测试
void test01()
{
Person p;//栈区数据,执行完后就会释放
}
int main()
{
//test01();
Person p; //这步执行后继续往下走,遇到pause就停止,输入任意键后才会执行销毁操作
system("pause");
return 0;
}
2、构造函数的分类和调用
#include<iostream>
using namespace std;
//构造函数的分类和调用
//1、有参构造
//2、无参构造
//3、拷贝构造
class Person
{
public:
Person()
//构造函数
{
cout<<"Person构造函数"<<endl;
}
Person(int a)
{
age = a;
cout<<"Person有参构造函数"<<endl;
}
//拷贝构造函数
Person(const Person &p)
{
//拷贝相同信息到这里来
cout<<"Person 拷贝构造函数调用"<<endl;
age = p.age;
}
//析构函数
~Person()
{
cout<<"Person的析构函数"<<endl;
}
int age;
} ;
//调用
void test()
{
//1、括号法
Person p; //默认
Person p1(10); //有参构造
Person p2(p1); //拷贝构造
cout <<"p1的年龄为:"<<p1.age<<endl;
cout <<"p2的年龄为:"<<p2.age<<endl;
//注意事项:调用默认构造时不要加()
//Person p3();//编译器认为i是函数声明 ,不会认为在创建对象
//2、显示法
Person p4;
Person p5 = Person(20); //有参构造
Person p6 = Person(p5); //拷贝构造
//注意事项1:
Person(10);//匿名对象 特点:当前行执行后,会立即收回匿名对象
cout<<"aaaaa"<<endl;
//注意事项2:
// 不要用拷贝构造函数 初始化匿名对象
//Person(p6); //重定义
//3、隐式转换法
Person p7 = 30;//相当于写了Person p7 = Person(30) 有参构造
Person p8 = p7;//拷贝
}
int main()
{
//测试
test();
system("pause");
return 0;
}
3、拷贝构造函数调用时机
#include<iostream>
using namespace std;
#include<string>
//拷贝构造函数调用时机
class Person
{
public:
Person()
{
cout<<"Person默认的构造函数"<<endl;
}
Person(int age)
{
Age = age;
}
//拷贝构造
Person(const Person &p)
{
cout<<"Person的拷贝构造"<<endl;
}
~Person()
{
cout<<"Person的析构函数"<<endl;
}
int Age;
} ;
//拷贝构造函数调用的三种情况
//1、使用一个创建完毕的对象初始化一个新对象
void test01()
{
Person p1;
p1.Age = 10;
Person p2(p1);
cout<<"P2的年龄:"<<p2.Age <<endl;
}
//2、值传递的方式给函数传值
void doWork(Person p)
{
}
void test02()
{
Person p;
doWork(p);
}
//3、以值方式返回局部对象
Person doWork2()
{
Person p1;
cout<<(int*)&p1<<endl;
return p1;
}
void test03()
{
Person p = doWork2();
cout<<(int*)&p<<endl;
}
int main()
{
test01();
//test02();
//test03();
system("pause");
return 0;
}
test01()结果:
test02()结果:
test03()结果:
4、构造函数调用规则
#include<iostream>
using namespace std;
//构造函数调用规则
//默认情况下,编译器会给一个类添加3个函数
//1、默认构造函数(无参、函数体为空)
//2、默认析构函数(无参、函数体为空)
//3、默认拷贝构造函数,对属性进行值拷贝
//调用函数规则如下:
//如果用户定义有参构造函数,C++不提供默认无参构造,但会提供默认拷贝构造
//用户定义拷贝构造函数,c++不会提供其他构造函数
//如果写了有参构造函数,编译器就不不会再提供默认构造函数 ,但是依然会提供拷贝构造
class Person
{
public:
Person()
{
cout<<"默认构造函数"<<endl;
}
//有参
Person(int age)
{
Age = age;
cout<<"有参构造函数"<<endl;
}
~Person()
{
cout<<"默认析构函数"<<endl;
}
//拷贝构造函数
Person(const Person &p)
{
Age = p.Age;
cout<<"拷贝构造函数"<<endl;
}
int Age;
} ;
void test()
{
Person p;
p.Age = 18;
Person p2(p);
cout<<"p2的年龄:"<<p2.Age<<endl;
}
void test01()
{
Person p(20);
Person p2(p);
}
int main()
{
//test();
test01();
system("pause");
return 0;
}
5、深拷贝与浅拷贝
#include<iostream>
using namespace std;
//深拷贝和浅拷贝
//1、深拷贝:在堆区重新申请空间,进行拷贝操作
//2、浅拷贝: 简单的赋值拷贝操作
//浅拷贝带来问题是堆区内存重复释放
//浅拷贝的问题用深拷贝进行解决
//堆区的数据是先进后出操作,浅拷贝就会引起堆区重复操作的问题,很容易出问题
class Person
{
public:
Person()
{
cout<<"默认构造函数"<<endl;
}
Person(int age,int height)
{
Age = age;
Height = new int(height);
cout<<"有参构造函数"<<endl;
}
~Person()
{
//析构代码,将堆区开辟数据做释放操作
if(Height != NULL)
{
delete Height;
Height = NULL;
}
cout<<"析构函数"<<endl;
}
Person(const Person &p)
{
cout<<"Person拷贝构造函数调用"<<endl;
Age = p.Age;
//Height = p.Height; 编译器默认实现的就是这行代码
//深拷贝操作
Height = new int(*p.Height);//解引用
}
int Age;
int *Height;
} ;
void test()
{
Person p1(18,160);
cout<<"p1的年龄:"<<p1.Age<<p1.Height<<endl;
Person p2(p1);
cout<<"p2的年龄:"<<p2.Age<<p2.Height<<endl;
}
int main()
{
test();
system("pause");
return 0;
}
6、初始化列表
#include<iostream>
using namespace std;
//初始化列表
//c++ 提供初始化列表用来初始化属性
class Person
{
public:
//传统初始化方法
// Person(int a,int b,int c)
// {
// m_A = a;
// m_B = b;
// m_C = c;
// }
void Print()
{
cout<<"m_A:"<<m_A<<endl;
cout<<"m_B:"<<m_B<<endl;
cout<<"m_C:"<<m_C<<endl;
}
//初始化列表方法
Person(int a,int b,int c):m_A(a),m_B(b),m_C(c)
{
}
private:
int m_A;
int m_B;
int m_C;
};
int main()
{
Person p1(1,2,3);
p1.Print();
system("pause");
return 0;
}
7、类对象作为类成员
#include<iostream>
using namespace std;
//C++类中的成员可以是另一个类的对象,我们称该成员为对象成员
class Phone
{
public:
//构造
Phone(string name)
{
m_PhoneName = name;
cout<<"Phone构造"<<endl;
}
//析构
~Phone()
{
cout<<"Phone析构"<<endl;
}
//成员属性
string m_PhoneName;
};
class Person
{
public:
//初始化列表可以告诉编译器用哪一个构造函数
Person(string name,string pName):m_Name(name),m_Phone(pName)
{
cout<<"Person构造"<<endl;
}
//析构
~Person()
{
cout<<"Person析构"<<endl;
}
//成员函数
void playGame()
{
cout<<m_Name<<"使用"<<m_Phone.m_PhoneName<<"牌手机!"<<endl;
}
//成员属性
string m_Name;
//phone类
Phone m_Phone;
};
void test()
{
//当类中成员是其他对象时,我们称该成员为 对象成员
//构造顺序是:先调用对象成员的构造,在调用本类构造
//析构顺序与构造相反
Person p("张三","Huawei pro") ;
p.playGame();
}
int main()
{
test();
system("pause");
return 0;
}
结果:
8、静态成员函数
#include<iostream>
using namespace std;
//静态成员就是在成员变量和成员函数前面加上关键字static,称为静态成员
//静态成员:
//1、静态成员变量:所有对象共享一份数据
//2、在编译阶段分配内存
//3、类内声明,类外初始化
//静态成员函数
//1、所有对象共享同一个函数
//2、静态成员函数只能访问静态成员变量
class Person
{
public:
//静态成员函数
static void func()
{
age = 10;//静态成员函数可以访问静态成员变量
num = 11;//静态成员函数,不可以访问非静态成员变量
cout<<"func()"<<endl;
}
//成员变量
static int age;//静态成员变量
static int num;//非静态成员变量
//静态成员函数也是有访问权限的
private:
static void func2()
{
cout<<"func2()"<<endl;
}
};
//类内声明,类外要初始化
int Person::age = 0;
int Person::num = 0;
void test()
{
//1、通过对象访问
Person p;
p.func();
//2、通过类名访问
Person::func();
//私有成员函数访问
//p.func2(); //访问失败,类外访问不到私有的静态成员函数
}
int main()
{
test();
system("pause");
return 0;
}
9、成员变量和成员函数分开存储
#include<iostream>
using namespace std;
//成员变量和成员函数是分开存储的
//只有非静态变量才属于类的对象上
class Person
{
int m_A;//非静态成员变量 属于类的对象上
static int m_B;//静态成员变量 不属于类的对象
void func(){}//非静态成员函数 不属于类对象上
static void func2(){} //静态成员函数
} ;
int Person::m_B = 0;
void test()
{
Person p;
//空对象占用空间的大小:1
//编译器会给空对象也分配一个字节空间,是为了区分空对象占内存的位置
//每个空对象也应该有一个独一无二的内存地址
cout<<"size of p:"<<sizeof(p)<<endl;
}
void test2()
{
Person p;
cout<<"size of p:"<<sizeof(p)<<endl;
}
int main()
{
test();
system("pause");
return 0;
}
10、this用法
#include<iostream>
using namespace std;
class Person
{
public:
Person(int age)
{
//this 指针指向被调用的成员函数所属的对象
this->age = age;
}
Person& addAge(Person p)
{
this->age += p.age;
//返回对象本身,this指向p3的指针,而*this指向的是p3的这个对象本体
return *this ;
}
int age;
};
//1、解决名称冲突
void test()
{
Person p2(18);
cout<<"p2的年龄:"<<p2.age<<endl;
}
//2、返回对象本身用*this
void test1()
{
Person p1(10);
Person p3(30);
p3.addAge(p1).addAge(p1).addAge(p1);//60
cout<<"p3的年龄:"<<p3.age<<endl;
}
int main()
{
//test();
test1();
system("pause");
return 0;
}
11、空指针访问成员变量
#include<iostream>
using namespace std;
//空指针也可以调用成员函数,但是也要注意有没有用到this指针
//如果用到this指针,需要加以判断保证代码的健壮性
class Person
{
public:
void showAge()
{
cout<<"this is Age"<<endl;
}
void showPerson()
{
//报错原因是因为传入的指针是NULL ,添加一个判断,防止出现错误,即使是NULL,也会直接跳过!
if (this == NULL)
{
return;
}
cout<<"Age= "<<this->m_Age<<endl;
}
int m_Age;
};
void test()
{
//创建一个空指针
Person *p1 = NULL;
// p1->m_Age=11;
//指针调用,忘记的话,记得复习
p1->showAge();
p1->showPerson();
}
int main()
{
test();
system("pause");
return 0;
}
12、const修饰成员变量
#include<iostream>
using namespace std;
//const修饰成员变量
//1、常函数
//加const后称常函数
//常函数内不可以修改成员属性
//成员属性声明时加关键字mutable,在常函数中依然可以修改
//2、常对象
//声明对象前加const称该对象为常对象
//常对象只能调用常函数
class Person
{
public:
void showPerson() const
{
//加const之后,就会只读的提示错误,这是一个常函数,只允许读操作
//m_Age = 10;
m_age = 20;
cout<<"this is Person"<<endl;
//cout<<"m_Age= "<<m_Age<<endl;
cout<<"m_age= "<<m_age<<endl;
}
int m_Age;
mutable int m_age;//特殊变量,在常函数中依然可以修改这个值,加关键字mutable
};
void test()
{
Person p1;
Person p2;
p2.showPerson();
//p1.showPerson();
}
int main()
{
test();
system("pause");
return 0;
}
--------------------------------------------------------------------------------
#include<iostream>
using namespace std;
//1、const修饰成员变量
class Man
{
public:
//这里是错误的
// Man(int h):height(h)
// {
// height = h;
// }
//可以使用初始化参数列表为成员变量赋值
Man(int h):height(h)
{
}
private:
const int height;//只能读,不能修改
};
int main()
{
system("pause");
return 0;
}
-------------------------------------------------------------------------------------
#include<iostream>
using namespace std;
//const修饰成员函数
class Person
{
public:
Person(int height,int weight);
void display() const;//声明一个成员函数
private:
int m_height;
int m_weight;
};
Person::Person(int height,int weight)
{
m_height = height;
m_weight = weight;
}
//成员函数只能应用成员变量而不能修饰成员变量
void Person::display() const
{
//m_height = 120;不能修改了,只读格式
cout<<"height is:"<<m_height<<endl;
cout<<"weight is:"<<m_weight<<endl;
}
int main()
{
Person p1(175,160);//定义一个person对象
p1.display();
system("pause");
return 0;
}
13、友元-全局变量做友元
#include<iostream>
using namespace std;
#include<string>
//想让类外特殊的一些函数或者类进行访问,就需要用到友元的技术
//友元就是让一个函数或者类访问另一个类中的私有成员
//关键字:friend
class Building
{
friend void goodBoy(Building *building);
public:
Building()
{
this->m_settingroom = "客厅";
this->m_beddingroom = "卧室";
}
public:
string m_settingroom;
private:
string m_beddingroom;
};
void goodBoy(Building *building)
{
cout<<"全局变量访问:"<<building->m_settingroom<<endl;
cout<<"全局变量访问:"<<building->m_beddingroom<<endl;
}
void test()
{
Building b;
goodBoy(&b);
}
int main()
{
test();
system("pause");
return 0;
}
14、普通函数做友元
#include<iostream>
using namespace std;
class CShop
{
public:
CShop(int size,int price);
void showSize();
void showPrice();
friend int ChangePrice(CShop &shop,int price);//声明一个函数为友元
private:
int m_size;
int m_price;
};
CShop::CShop(int size,int price)
{
m_size = size;
m_price = price;
}
void CShop::showSize()
{
cout<<"size is :"<<m_size<<endl;
}
void CShop::showPrice()
{
cout<<"Price is :"<<m_price<<endl;
}
//友元函数的定义
int ChangePrice(CShop &shop,int price)
{
shop.m_price = price;//友元函数中访问私有变量
return shop.m_price;
}
int main()
{
//创建一个对象
CShop shop(100,2000);
shop.showSize();
shop.showPrice();
//调用友元函数
ChangePrice(shop,3000);
shop.showSize();
shop.showPrice();
system("pause");
return 0;
}
15、友元成员变量
#include<iostream>
using namespace std;
//友元不仅可以时一般的函数,还可以是类中的成员函数
class CShop;//提前声明表示稍后要定义的类
class CCompany
{
public:
void Display(CShop &shop);
} ;
class CShop
{
public:
CShop(int size,int price);
friend void CCompany::Display(CShop &shop); //CCompany中的成员函数友元
private:
int m_size;
int m_price;//私有 变量
};
void CCompany::Display(CShop &shop)
{
cout<<"the price of shop is :"<<shop.m_price<<endl;
cout<<"the size of shop is :"<<shop.m_size<<endl;
}
CShop::CShop(int size,int price)
{
m_price = price;
m_size = size;
}
int main()
{
CShop shop(200,500);
//shop.Display();
CCompany company;//调用友元
company.Display(shop);
system("pause");
return 0;
}
16、类做友元
//将整个类都声明为友元
#include<iostream>
using namespace std;
class CShop;//提前声明表示稍后要定义的类
class CCompany
{
public:
void Display(CShop &shop);
} ;
class CShop
{
public:
CShop(int size,int price);
friend CCompany;
private:
int m_size;
int m_price;//私有 变量
};
void CCompany::Display(CShop &shop)
{
cout<<"the price of shop is :"<<shop.m_price<<endl;
cout<<"the size of shop is :"<<shop.m_size<<endl;
}
CShop::CShop(int size,int price)
{
m_price = price;
m_size = size;
}
int main()
{
CShop shop(200,500);//定义一个shop类初始化
//shop.Display();
CCompany company;//调用友元
company.Display(shop);
system("pause");
return 0;
}
类和对象结束!!!好累,这节真的很难理解,尽量还是结合书配套学,细节的东西太多了,还是得多敲代码,找问题的!!!