博主水平有限,不足之处如能斧正,感激不尽!
通过前两篇类和对象的讲解,我们对类和对象有了大概的认识,此篇主要是补充类和对象的其他语法,主要有:
我们提过,构造函数体内对属性的“初始化”实际上是赋值,到了函数体内,属性已经定义好了。那我们怎么能给属性真正初始化呢?
这就需要用到初始化列表。
初始化列表是对象的属性定义的地方。
某些属性必须初始化,而不是定义后赋初值。
如
className(datatype mem1, datatype mem2):_mem1(mem1),_mem2(mem2)
{}
函数体前,用冒号开头,通过括号给成员初始化,成员的初始化用逗号隔开。
class B
{
public:
B(int b)
{
_b = b;
}
private:
int _b;
};
class A
{
public:
A(const int a1, int& a2, int b):_a1(a1), _a2(a2), _bb(b)
{}
private:
const int _a1;
int& _a2;
B _bb;
};
int main()
{
int a1 = 10;
int a2 = 20;
int b = 30;
A aa(a1, a2, b);
return 0;
}
如果不适用初始化列表初始化:
尽量都用初始化列表来初始化:用了一定没问题,不用可能有问题。
单参构造在类型合适的时候,会被赋值运算符重载触发 类型转换 的功能。
听着很抽象,结合explicit来理解。
explicit 是用来 禁用函数自动类型转换 的关键字
有时我们不想要这样触发的类型转换
explicit A()
{
//...
}
接下来就看看,有无explicit修饰的构造有什么区别。
class A1
{
public:
explicit A1(int a):_a(a)
{}
private:
int _a;
};
class A2
{
public:
explicit A2(int a):_a(a)
{}
private:
int _a;
};
int main()
{
//单参构造函数,用函数调用触发,不会发生类型转换
A1 aa1(10);
//单参数构造函数,用赋值运算符重载触发,会发生类型转换
A2 aa2 = 20;//error:No viable conversion from 'int' to 'A2'
return 0;
}
和整个类深度绑定的成员。
有些成员,需要能够被同类的所有对象访问。
static成员:
static成员变量
static成员函数
1. static成员变量:类内声明,类外定义初始化
class A
{
public:
A()
{
//...
cnt++;
}
A(const A& aa2)
{
//...
cnt++;
}
void Printcnt()
{
cout << cnt << endl;
}
private:
int _mem = 0;
//计算调用了几次构造和拷贝构造
static int cnt;
};
int A::cnt = 0;
A test(A aa)
{
return aa;
}
int main()
{
A aa1;
A aa2(aa1);
test(aa1);
aa1.Printcnt();
return 0;
}
:4
2. static成员函数
class A
{
public:
static void Print()
{
cout << "className: A" << endl;
}
private:
int _mem = 0;
};
int main()
{
A aa1;
A aa2;
A aa3;
aa1.Print();
aa2.Print();
aa3.Print();
return 0;
}
:className: A
className: A
className: A
:不可以,没有this指针,非静态成员函数的第一个this形参接收不到。
可以,静态成员函数属于整个类,类外指定类域即可调用,类内的成员函数更是可以直接调用。
this指针具有常性的成员函数。
带上const对象一起玩。
默认情况下,this的类型是 classname* const,尽管它是隐式传递的,也还是要遵循初始化规则,这也代表,当对象为常量对象,this指针传参会不匹配:
const classname* const 传给 classname* const
所以引入了const成员函数,
来声明此函数的this是const className* const。
void Print() const
{
//...
}
放在参数列表后面,表示此成员函数的this指针为 const className* const this。
不用改变对象的函数全声明成const成员函数。
有些时候,我们实现函数时,需要在类外访问类内的私有成员,但是又不想通过成员函数的形式,就有了友元。
是对非成员函数对类成员的访问权限的声明(声明后可以访问类内成员)。
虽然是满足了需要,但是这也破坏了类的封装,尽量少用。
有时需要允许特定的函数访问私有成员。
class A
{
public:
friend void PrintMem(A& aa);
private:
int _mem = 0;
};
void PrintMem(A& aa)
{
cout << aa._mem << endl;
}
int main(int argc, const char * argv[])
{
A aa;
PrintMem(aa);
return 0;
}
:0
下图就印证了:友元函数的声明仅仅是声明了“函数的访问权限”,而非“对函数本身的声明”。
基本和友元函数一样。
class A
{
public:
friend class B;
private:
int _mem = 10;
};
class B
{
public:
void PrintA()
{
cout << _aa._mem << endl;
}
private:
int _mem = 0;
A _aa;
};
int main(int argc, const char * argv[])
{
B bb;
bb.PrintA();
return 0;
}
类中类,但它是独立的类。
class A
{
public:
class B
{
public:
void Print(A& aa)
{
cout << "内部类B访问外部类A的static成员:" << _a1 << endl;
cout << "内部类B访问外部类A的普通成员:" << aa._a2 << endl;
}
private:
int _b = 30;
};
private:
static int _a1;
int _a2 = 20;
};
int A::_a1 = 10;
int main()
{
A aa;
A::B bb;
bb.Print(aa);
return 0;
}
:内部类B访问外部类A的static成员:10
内部类B访问外部类A的普通成员:20
破坏封装,尽量少用。
没有名字,只在当前行生效(下一行前自动调用析构)的对象。
有时候,我们实例化一个对象仅仅只是为了调用它的函数或其他简单的操作,这时候要实例化出一个普通对象,用完还要等到出生命周期才调用析构——不如弄个临时的用用。
class A
{
public:
void Print()
{
cout << _aa << endl;
}
~A()
{
cout << "~A()" << endl;
}
private:
int _aa;
};
int main()
{
A().Print();
cout << "------------" << endl;
return 0;
}
:10
~A()
------------
今天的分享就到这里啦
这里是培根的blog,期待与你共同进步!
下期见~