在C++中,成员变量和成员函数分开存储。计算类所占内存大小时,只有非静态成员变量才属于类的大小,其余都不计算在类的内部。
空类创建的对象占的字节数为1
类对象的构造顺序:
类的初始化方式:
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)
{
}
注:推荐使用初始化列表的方式,直接对成员变量进行初始化;而传统的初始化方式调用了默认构造函数,然后在构造函数中完成了赋值操作,所以体现出了效率的差异。
以下三种情况必须使用初始化列表:
#include
using namespace std;
class Test
{
public:
Test(int, int, int)
{
cout<<"Test"<<endl;
}
private:
int x;
int y;
int z;
};
class Mytest
{
public:
Mytest():test(1, 2, 3){
cout << "Mytest" << endl;
}
private:
Test test;
};
class Test
{
public:
Test():a(10) { }
private:
const int a;
};
或者
class Test
{
public:
Test(int a):a(a) {}
private:
int& a;
};
class Test
{
public:
Test(){}
Test(int x):m_x(x) {}
void show() {cout<<m_x<<endl;}
private:
int m_x;
};
class Mytest:public Test
{
public:
Mytest():Test(110) {}
};
初始化成员列表使用注意事项:
构造函数列表初始化不是按照列表的顺序,而是按照变量的声明顺序。
例如:
#include
using namespace std;
class Test
{
public:
Test(int i): m_j(i), m_i(m_j) { }
int get_i() const{
return m_i;
}
int get_j() const{
return m_j;
}
private:
int m_i;
int m_j;
};
int main()
{
Test test(10);
cout << test.get_i << endl << test.get_j << endl;
return 0;
}
输出结果:随机数 和 10
一般const成员函数不能修改成员变量,但是只要成员变量被声明为mutable,则在const成员函数中也可以修改它。
mutable不能修饰静态成员变量
静态成员变量的作用:
使用:
class Rectangle
{
private:
static int count;
int high, width;
public:
Rectangle() {count++;}
Rectangle(int high_value, int width_value = 5);
~Rectangle() {count--;}
static int get_count() {return count;}
};
int Rectangle::count = 0;
注意:静态成员变量 需要类内声明,类外初始化 (其实是定义,分配内存)
static静态成员变量的特性:
构造函数用来初始化类对象的数据成员,只要类的对象被创建,就会自动调用构造函数
构造函数的语法:
类名() { }
构造函数分类:
Person()
{
cout<<"Person的无参构造"<<endl;
}
或者
Person(int a=10)
{
cout<<"Person的无参构造"<<endl;
}
Person(int age)
{
m_age = age;
}
Person(const Person &p)
{
m_age = p.age;
}
编译器会自动生成默认构造函数的情况:
通过拷贝构造函数实现类对象之间的拷贝过程
参数:
拷贝构造函数是一种特殊的构造函数,函数名称必须和类名称相同,第一个参数必须是本类型的一个引用变量。
注意:必须是引用类型,否则会构成递归调用。
默认拷贝构造函数
形式:
编译器一般会给我们自动生成默认拷贝构造函数,只是使用老对象的数据成员对新对象的数据成员进行赋值操作。一般代码如下 :
Rectangle(const Rectangle &r)
{
m_height = r.height;
m_width = r.width;
}
默认拷贝构造函数存在的问题:
静态成员的复制问题
默认拷贝构造函数不会处理静态成员变量,成员变量复制的时候不会复制静态成员变量。
比如一个类中静态成员变量来统计对象的个数,在用一个对象rec1复制出对象rec2;当输出此时的对象个数的时候,仍显示是1个。此外,在销毁对象的时候,由于类的析构函数会调用两次,此时的计数器将边为负数。
解决方法:自己定义拷贝构造函数,在拷贝构造函数中对计数器进行操作。
指针的复制问题(浅拷贝和深拷贝)
浅拷贝:指的是对对象进行拷贝的时候,只对对象中的数据成员进行简单的赋值。多数情况下浅拷贝已经能够很好地解决问题,但是当出现动态成员,浅拷贝就会出现问题。
解决方法 :
一是将拷贝构造函数设置为私有,防止默认拷贝构造函数的调用,这样拷贝的时候就会报错
二是在自定义的拷贝构造函数中执行深拷贝(在堆区重新申请空间,进行拷贝操作),有了自定义拷贝构造函数就不会有默认拷贝构造函数
默认情况下,C++编译器至少给一个类添加三个函数:
构造函数调用规则:
作用:释放对象使用的资源并销毁非static成员,不能重载,只能有唯一一个。
当析构函数未定义时,编译器自动生成,对象被销毁时自动调用。
C++类中的成员可以是另一个类的对象,我们称该成员为 对象成员
例如
class A { }
class B
{
A a;
}
B类中有对象A作为成员,A为对象成员
那么当创建B对象时,A与B的构造和析构顺序时谁先谁后?
A构造——B构造——B析构——A析构
当其他类对象作为本类成员,构造时先构造类对象,再构造自身;析构的顺序与构造相反
为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了 inline 修饰符,表示为内联函数。
定义在类中的成员函数默认都是内联的,如果在类定义时就在类内给出函数定义,那当然最好。如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上 inline,否则就认为不是内联的。
class A
{
int Foo(int a, int b) {} //内联函数
};
最好采用分文件编写:
//头文件
class A
{
public:
void Foo(int a, int b);
};
//定义文件
inline void A::Foo(int a, int b) { }
const成员函数本质上是隐式修改this指针的类型
this指针本质上是指针常量,指针的指向不能被修改。在类成员函数后面加const,修饰的是this指向,让指针指向的值不可以被修改。
常函数:
常对象:
静态成员函数为整个类所有,只能访问静态成员变量和静态成员函数。
友元的目的:可以让一个函数或者类访问另一个类中的私有成员
class Building
{
friend void GoodGay(Building *building);
public:
Building()
{
this->m_sittingroom = "客厅";
this->m_bedroom = "卧室";
}
string m_sittingroom;
private:
string m_bedroom;
};
void GoodGay(Building *building)
{
cout << building->m_sittingroom << endl;
cout << building->m_bedroom << endl;
}
class Building
{
friend class GoodGay;
public:
Building();
string m_sittingroom;
private:
string m_bedroom;
};
class Building;
class GoodGay
{
public:
GoodGay();
void visit();
void visit2();
private:
Building *building;
};
class Building
{
friend void GoodGay::visit();
public:
Building();
string m_sittingroom;
private:
string m_bedroom;
};