类
类中的成员默认权限是private
private: 仅在类内部可以访问
protected:子类可以访问
public:外部可以访问
#include <iostream>
using namespace std;
const double pi = 3.14;
//创建类
class Circle
{
public:
double calculate()
{
return 2 * pi * m_R;
}
int m_R;
private:
int m_a;
};
int main()
{
Circle c; //创建对象
//c.m_a = 4; 错误,priate变量和protected变量仅为类内部使用,对象不能调用。
c.m_R = 10; //public的对象可以调用
cout << c.calculate();
}
建议:将所有成员变量设置为private,使用public的get和set方法设置和获取私有变量的值,哪些可读可写是否添加get或者set,都可以掌控。
创建对象的几种方式
c++中用new和delete关键字来代替malloc和free
class 类保存在栈区,new出的对象保存在堆区。
#include <iostream>
using namespace std;
class Person
{
public:
Person()
{
cout << "构造函数" << endl;
}
~Person()
{
cout << "析构函数" << endl;
}
};
int main()
{
//第一种:
Person p1; //在栈区创建对象,所在函数结束会自动释放对象 不需要delete
//第二种:
Person(); //创建一个临时匿名对象
Person p = Person();//效率比第一个低,这里先右边创建一个匿名对象然后调用拷贝构造给左边对象p;
//第三种:
Person *p2 = new Person; // new对象返回的是指针, 在堆上创建对象,new之后需要手动delete释放对象 //构造函数
//new的对象会返回该类型的指针
//当我们想释放堆区空间,则使用delete关键字
delete p2; // 析构函数
Person *p3 = NULL; //定义对象指针, 不分配内存
}
对象占用内存
#include <iostream>
using namespace std;
class Person
{
public:
int m_A;
double m_B;
void func(){};
static int m_C;
};
void test1()
{
cout << "size of (Person) = " << sizeof(Person) << endl;
}
int main()
{
test1();
}
//空类 大小1
//有一个int成员变量 4;
//有2个t成员变量 16; 字节对齐,int需要和double对齐,double 8字节
//函数不占内存
//static 属性,静态成员变量不占对象内存。
//结论:只有非静态成员变量才属于对象。
构造与析构函数
构造函数的用处:初始化成员变量。
构造和析构,也就是初始化和清理
创建对象时,系统自动调用构造和析构函数,如果没有定义则系统提供默认构造和析构函数。
构造函数规则
系统会提供三个构造函数:无参构造,拷贝构造,析构函数。
系统提供三个构造函数规则:
- 当用户定义构造函数,系统就不提供默认无参构造。但是系统会提供默认拷贝构造函数。
- 当用户定义拷贝构造,则系统不提供默认无参构造和拷贝构造。
#include <iostream>
//使用iostream我们就可以使用cout和cin
using namespace std;
class Person
{
private:
/* data */
public:
//构造函数
//与类名相同无返回值,可重载。
Person();
Person(int a);
//拷贝构造函数 :把引用传进去,使用const不能修改该对象,拷贝构造必须加const
Person(const Person &p);
//析构函数,不能重载,无参数
~Person();
};
Person::Person()
{
cout << "无参数构造" << endl;
}
Person::Person(int a)
{
cout << "有参数构造" << endl;
}
Person::Person(const Person &p)
{
cout << "copy构造" << endl;
}
Person::~Person()
{
cout << "析构" << endl;
}
int main()
{
Person p1; // 创建对象,调用无参构造函数不加小括号 //Person p1();
Person p2(2); // 创建对象,调用有参第一中方式
Person p22 = Person(22); // 创建对象,调用有参第二种方式: Person(22)是创建匿名对象,然后把它给p22
Person p3(p1); // 创建对象,调用拷贝构造函数 第一种方式
Person p33 = Person(p1); // 创建对象,调用拷贝构造函数 第二种方式
cout << "------main方法结束。" << endl; //方法结束之后才会调用对象的析构函数。
}
/*
无参数构造
有参数构造
有参数构造
copy构造
copy构造
------main方法结束。
析构
析构
析构
析构
析构
*/
explicit关键字
防止隐式类型转换。
在此构造函数前加explicit则第二种调用有参构造方式失效。
Person p2(2); // 创建对象,调用有参第一中方式
//Person p22 = Person(22); // 就不能通过该方式进行调用
深拷贝与浅拷贝
C++面试题之浅拷贝和深拷贝的区别
C++深拷贝与浅拷贝
浅拷贝:用户没有定义拷贝构造方法,系统调用默认拷贝构造。会进行简单的值拷贝,如果属性里有指向堆空间的数据,那么简单的浅拷贝会导致重复释放内存。
深拷贝:用户自己定义拷贝构造函数。 对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一个功能类似的拷贝构造函数。但是当类持有其它资源时,例如动态分配的内存、指向其他数据的指针等,默认的拷贝构造函数就不能拷贝这些资源了,我们必须显式地定义拷贝构造函数,以完整地拷贝对象的所有数据。
初始化的方式
初始化两种方式:
- 传统初始化
class Person
{
public:
Person(int a, int b, int c)
{
m_a = a;
m_b = b;
m_c = c;
}
int m_a;
int m_b;
int m_c;
};
int main()
{
Person p1(10, 20, 30); // 创建对象调用有参构造
cout << "m_a :" << p1.m_a << endl; //10
cout << "m_b :" << p1.m_b << endl; //20
cout << "m_c :" << p1.m_c << endl; //30
}
- 初始化列表初始化
class Person
{
public:
/*
Person(int a, int b, int c)
{
m_a = a;
m_b = b;
m_c = c;
}
*/
//构造函数 : 属性(参数),属性(参数){}
Person(int a, int b, int c): m_a(a),m_b(b),m_c(c)
{}
int m_a;
int m_b;
int m_c;
};
int main()
{
Person p1(10, 20, 30); // 创建对象调用有参构造
cout << "m_a :" << p1.m_a << endl; //10
cout << "m_b :" << p1.m_b << endl; //20
cout << "m_c :" << p1.m_c << endl; //30
}
类对象作为类成员
当类对象做为类成员时候,构造顺序先将类对象一一构造,然后构造自己。当析构的时候顺序相反。
空指针访问成员函数
如果成员函数中没有调用成员变量则可以调用成员函数。
如果成员函数中包含成员变量则不可以调用。
#include <iostream>
using namespace std;
class Person
{
public:
void show()
{
cout << "show" << endl;
}
void show2(){
show();
}
void showAge()
{
cout << m_Age << endl;
}
int m_Age;
};
void test1()
{
Person *p = NULL;
p->show(); //可以访问
p->show2();//可以访问
//p->showAge(); //Segmentation fault: 11 不可以
}
int main()
{
test1();
}