C++_类和对象01_封装、初始化、对象特性、友元_学习笔记

面向对象三大特性:封装、继承、多态

1. 封装

class 类名{ 权限 : 属性/行为}
类中的属性和行为统一称为成员。
属性 亦称为成员属性、成员变量;行为 亦称为成员行为

//设计一个圆类,求周长
const double PI = 3.14;
class Circle
{
public://公共权限
	int m_r; //属性 用变量
	double calZC() //行为 用函数
	{
		return 2*PI*m_r;
	}
};
int main(){
	Circle c1; //实例化一个对象
	c1.m_r = 10; //给对象属性赋值
	ZC = c1.calZC(); 
}

访问权限有三种:
public:类内类外都可访问
protected:类内可访问,类外不可访问,儿子可以访问父亲中的保护内容
private:类内可访问,类外不可访问,儿子不可以访问父亲中的私有内容
struct默认权限为public,class默认权限为private。
成员属性设为私有,但通过公共的行为进行属性修改,方便控制权限。

class student
{
public:
    void setname(string name)
    {
        name = name;
    }
    string getname()
    {
        return name;
    }
private:
    string name; //wr
    int age; //r
    string idol; //w

};
int main()
{
    student p;
    // p.name = "张三" 会报错,因为name是私有
    p.setname("张三");//但是可以通过公共行为对私有属性修改
    //通过public的行为设置,可以实现读写权限的控制
    return 0;
}

2. 初始化和清理

利用构造函数析构函数进行初始化清理。如果不提供,编译器会提供空实现。
战吼:构造函数 类名(){}
构造函数没有返回值;可以有参数,可重载;创建对象时会自动调用,且只调用一次。
亡语:析构函数 ~类名(){}
析构函数没有返回值;不能有参数,不可重载;对象销毁前会自动调用,且只调用一次。

class Person
{	
	Person(){...}//无参构造
	Person(int age){m_age = age}//有参构造
	Person(const Person &p){m_age = p.age}//拷贝构造 //将传入的对象所有属性拷贝到自己身上
};
int main()
{
	Person p1;//创建对象后会执行无参构造函数。千万不要加括号,否则会认为是函数声明。
	
	Person p2_1(10);//创建对象后会执行有参构造函数
	Person p2_2 = Person(10);//效果和上一句一样
	Person p2_3 = 10;//效果和上一句一样
	
	Person p3_1(p2_1);//创建对象后会执行拷贝构造函数。且p3与p2相同。
	Person p3_2 = Person(p2_2);//效果和上一句一样
	Person p3_3 = p2_3;//效果和上一句一样
	
	Person(10)//匿名对象 特点:当前行执行结束后,自动回收掉。
}

2.1 构造函数调用规则

默认情况下,C++编译器至少给一个类添加3个函数

  1. 默认构造函数,无参,函数体为空。
  2. 默认析构函数,无参,函数体为空。
  3. 默认拷贝构造函数,对属性进行拷贝。

调用规则:

  1. 如果用户定义有参构造函数,编译器不再提供默认无参构造,但是会提供默认拷贝构造。
  2. 如果用户定义拷贝构造函数,编译器不再提供其他构造函数。

2.2 深拷贝和浅拷贝(面试常考)

浅拷贝:简单赋值拷贝操作
深拷贝:在堆区重新申请空间,进行赋值
析构函数,可以将堆区开辟的数据做释放操作

class Person
{
    
public:
    Person(){cout << "默认构造" << endl;}
    Person(int age, int height)
    {
        m_age = age;
        m_height = new int(height);  //在堆区开辟空间
        cout << "有参构造" << endl;
    }
    ~Person()
    {
        if (m_height != NULL)
        {
            delete m_height;
            m_height = NULL;
        }
        cout << "析构" << endl;
    }
    int m_age;
    int* m_height;
};

上述对象,如果用Person p2(p1)//编译器提供的拷贝构造函数,进行浅拷贝,会在析构函数中重复释放内存,造成报错。
浅拷贝带来的问题是堆区内存重复释放。
所以要自己实现拷贝构造函数来解决问题:

Person(const Person &p)
{
	m_age = p.age;
	//编译器默认实现为:m_height = p.m_height
	m_height = new int(*p.m_height);
}

2.3 初始化列表

构造函数(): 属性1(值1),属性2(值2), 属性3(值3);

class Person
{
public:
	int m_a,m_b,m_c;
	Person(int a, int b, int c):m_a(a),m_b(b),m_c(c){}
};
int main()
{
	Person p(30,20,10);
}

3对象特性

3.1类对象作为类成员

套娃,类中的成员可以是另一个类。

class phone
{
public:
	string p_number;
	string p_type;
};
class person
{
	public:
	srting m_name;
	phone m_phone;
};

实例化person时也会实例化phone。
顺序为:phone构造->person构造->person析构->phone析构。析构的顺序与构造相反。

3.2静态成员

使用static关键字

  1. 静态成员变量
    (1) 所有对象共享同一份数据(同一个内存)
    (2)编译时分配内存
    (3)类内声明,类外初始化
class Person
{
public:
	static int m_A;//类内声明
};
int Person::m_A = 100;//类外初始化
//静态成员变量不属于某个对象
int main(){
	Person p1;
	Person p2;
	p2.m_A = 200;
	cout << p1.m_A << p2.m_A << endl; // 通过对象访问。此时两个输出结果都是200
	cout << Person::m_A << endl; //也可以通过类名访问
}
  1. 静态成员函数
    (1)所有对象共享同一个函数
    (2)静态成员函数只能访问静态成员变量
class Person
{
public:
	static int m_A;
	int m_B;
	static void func()
	{
		m_A = 100;//合法
		m_B = 100;//非法
	}
};
int main()
{
	//通过对象访问
	Person p;
	p.func();
	//通过类名访问
	Person::func();
}

类内成员对象和成员函数分开存储。只有非静态成员变量才属于类的对象上。
非静态成员变量,属于类的对象上;
静态成员变量,不属于类的对象上;
非静态成员函数,不属于类的对象上。
空类占用空间为1。

3.3 this指针

this指针指向被调用的成员函数所属对象。返回对象本身用*this

class Person
{
public:
	int age;
	Person(int age)
	{
		this->age = age;//this指针可解决
	}
	Person& PersonAddAge(Person &p)//返回值要加引用
	{//this指向p2的指针,*this指向p2的本体。
		this->age += p.age;
		return * this;
	}
}
int main()
{
	Person p1(10);
	Person p2(20);
	p2.PersonAddAge(p1).PersonAddAge(p1).PersonAddAge(p1);
}

3.4const修饰成员函数

常函数内成员属性不可修改。(原理:this指针本身不可修改,加了个const之后连值也不能修改了)
但是成员属性声明时加mutable,可以修改。
常对象只能调用常函数。

class Person
{
public:
	int m_A;
	mutable int m_B;
	void func01() const
	{
		m_A = 100; //这是非法的,因为是常函数,不能修改
		m_B = 100; //这是合法的,因为m_B是mutable的
	}
	void func02(){}	
}
int main()
{
	const Person p; //常对象
	p.m_A = 100; //这是非法的
	p.m_B = 100; //这是合法的
	p.func01(); //这是合法的
	p.func02(); //这是非法的,常对象只能调用常函数
	
}

4.友元

4.1 全局函数做友元

在类中使用friend声明全局函数,可以使该函数访问该类的私有属性。

class building
{	//goodgay()函数是building的友元,可以访问building的私有成员
    friend void goodgay(building* bd); 
public:
    building()
    {
        m_sittingroom = "客厅";
        m_bedroom = "卧室";
    }
    string m_sittingroom;
private:
    string m_bedroom;
};

void goodgay(building * bd)
{
    cout << bd->m_sittingroom << endl; 
    cout << bd->m_bedroom << endl;//如果不用friend修饰,这句是非法的。
}

int main()
{
    building bd;
    goodgay(&bd);
    return 0;
}

4.2 类做友元

class Building
{	//GoodGay类是building的友元,可以访问building的私有成员
	friend class GoodGay;
public:
	Building()
	{
		m_sittingroom = "客厅";
		m_bedroom = "卧室";
	}
	string m_sittingroom;
private:
	string m_bedroom;
};

class GoodGay
{
public:
	GoodGay()
	{
		//创建一个Building
		building = new Building;
	}
	Building* building;
	void visit()//访问Building中的属性
	{
		cout << building->m_sittingroom << endl;
		cout << building->m_bedroom << endl;
	}
};

int main()
{
	GoodGay gg;
	gg.visit();
}

4.3 成员函数做友元

跑的程序有问题,暂时不写上来。

  • 17
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值