标签:protected ror 撤销 系统 示例 拷贝构造 error str 资源
01.概念:对一组具有相同特征的对象的描述,创建对象的模板
02.构成:数据成员 + 成员函数(可对数据成员进行的操作)
03.成员控制访问:
public 成员的访问不受限制,在程序中的任何地方都可以访问一个类的public成员 (只有提供给外界的API用该限制)
private 成员只能在本类和友元中访问
protected 成员只能在本类,友元和派生类中访问
04.注意: 类定义中不可对数据成员进行初始化,应在构造函数中初始化;
数据成员可为任意C++类型,如果未见类的定义或者类型未定义完,则类型只能为这些类型的指针或引用类型
成员函数的定义可以在类定义外,也可以在类定义中
类成员函数能够重载,遵循全局函数名的重载规则
类定义外进行函数定义或数据使用需要使用<类名>::受限,成员函数定义中使用重名全局函数则要加上全局域解析符“::”
类定义构成类作用域
定义格式:
class <类名>
{
public:
<成员描述>
private:
<成员描述>
protected:
<成员描述>
};
A a1; //直接创建-对象
A a2[100]; //直接创建-对象数组
A *p = new A; //间接创建-对象(用new & delete创建撤销)
//与普通变量一样,分为 全局对象 和 局部对象
//成员函数的操作
a1.f(1); //非动态对象操作 <对象>.<类成员>
p->f(2); //动态对象操作 <对象>-><类成员>
(*p).f(3); //or动态对象操作 (*<对象指针>).<类成员>
a1 = a2; //对象间赋值操作 将赋值操作符右边的数据成员的值分别赋给左边对象的数据成员
//格式 <类名> *const this;
class A
{
public:
int f(int x){ val = x; } //编译时,将被编译为 int f(A *const this, int x){ val = x; }
private:
int val;
};
//如果在成员函数中要把this所指向的对象作为整体来操作,则必须显示地使用this指针
? 1.概念
class A
{ int x;
string s;
public:
A() { x = 0; } //在对象类中定义或声明的与类同名、无返回值类型的成员函数
//在创建对象时,构造函数会被自动调用,对象创建后不可再调用
A(string y) { s = y, x = 0; }
...
};
A a1;
A a2("hello"); //在创建对象时可指定构造函数的使用
? 2.注意:
? 构造函数可重载,不带参数的构造函数被称为默认构造函数 (如果在对象类中提供了任何构造函数,则编译程序不再提供默认构造函数)
? 类的构造函数一般为公开的,如果将其声明设置为私有,则只能在本类和友元中创建该类对象
? 创建动态的对象数组时,只能用默认构造函数来初始化
? A *p = new A[20];
? 常量数据成员 和 引用类型数据成员,不能在说明它们时初始化,也不能采用赋值操作对它们初始化
? 成员初始化的顺序 = 在类中的说明次序 != 成员初始化表中的次序
//错误示例
class A
{
public:
A()
{
val = 0;
content = 3; //Error
z = 9; //Error
}
private:
int val;
const int content;
int& z;
};
//正确示例
class A
{
public:
A(): z(9), content(3) //成员初始化表
{
val = 0;
}
private:
int val;
const int content;
int& z;
};
? 概念 对象消亡时,自动调用的,处理申请的动态内存等的善后函数
? 如果对象创建后申请了资源,并且在对象消亡前没有归还这些资源,则应自定义析构函数以在对象消亡时归还对象申请的资源
class A
{
public:
A();
~A(); //名为‘~<类名>‘,没有参数和返回值类型的特殊成员函数 (使用delete收回内存)
...
private:
int x;
...
};
? 创建包含成员对象的对象时,对成员对象的初始化是由成员对象类的构造函数来实现的
? 如需要调用成员对象类的非默认构造函数对成员对象初始化,则需要在包含成员对象的类的构造函数的成员初始化表中显示指出
class A
{
int val;
A(int x){ val1 = x;}
};
class B
{
int val2;
A a1;
B(int x1, int x2): a1(x2){ val1 = x2; } //指明成员对象构造函数
{
val2 = x1;
}
};
? 重点
? 构造顺序:
? 创建含有成员对象的对象时,先调用本身类的构造函数,在进入本身类的构造函数的函数体之前,先调用成员对象类的构造函数初始化成员对象,然后再执行本身的构造函数。
? 当包含多个成员对象,成员对象类的构造函数顺序 = 成员对象在类中说明顺序
? 析构顺序:
? 当含有成员对象的对象消亡时,先调用本身类的析构函数,本身类的析构函数执行完后,再调用成员对象类的析构函数
? 当包含多个成员对象,成员对象类的析构函数顺序 = 逆序(成员对象在类中说明顺序)
//创建对象时,用另一已有对象进行初始化则会调用 拷贝构造函数class A{....public: A(); A(const A& a); //格式 <类名>(const <类名>&);};
//调用 拷贝构造函数 的情况
//1.定义对象时
A a1; //默认构造函数对a1初始化
A a2(a1); //拷贝构造函数用a1对a2初始化,或为a2=a1/A a2 = A(a1)
//2.把对象作为值参数传递给函数时
void f(A x);A a1;f(a1); //调用时创建新参对象x,并调用拷贝构造函数,用对象a1初始化x
//3.把对象作为返回值时
A f(){ A a; ... return a; //创建一个A临时对象,并调用拷贝构造函数,用对象a对其初始化}
? 类中没有定义拷贝构造函数,则编译程序会为其提供一个隐式的拷贝构造函数,行为为:逐个成员拷贝初始化
? 由此引发bug:当成员中含有指针时,实际上是将新旧两个对象的指针成员指向同一内存地址
//错误示范class A
{ int x, y;
char* p;public: A(char* str)
{ x = 0;
y = 0;
p = new char[strlen(str) + 1];
strcpy(p, str);
}
~A() {delete []p; p = NULL; }
...//未定义拷贝构造函数
};
A a1("hello world");A a2(a1);
//此时a1, a2的p成员指向同一个内存地址
//修正-为A添加自定义拷贝构造函数
A::A(const A& a)
{//省略了this指针
x = a.x;
y = a.y;
p = new char[strlen(a.p) + 1];
strcpy(p, a.p);}
? 当类定义中含有成员对象,系统提供的默认拷贝构造函数会调用成员对象的拷贝构造函数,而自定义的拷贝构造函数则默认调用成员对象的默认构造函数
? 若要修改,可在自定义拷贝构造函数的成员初始化表中显示指出调用成员对象类的构造函数。
B(const B& b): a(b.a) { z = b.z; } //在B类拷贝构造函数中指定A类成员对象的构造函数为A(int x) { z = x; }
标签:protected ror 撤销 系统 示例 拷贝构造 error str 资源
原文地址:https://www.cnblogs.com/hibna-blog/p/14806698.html