static
在声明(声明都是在类体内完成的)::
来指明所属的类。
#include
using namespace std;
class Point{
// Point类定义
public: // 外部接口
Point(int xx=0,int yy=0):x(xx),y(yy){
// 构造函数
// 在构造函数中对count累加,所有对象共同维护同一个count
count++;
}
Point(Point &p){
\\ 拷贝构造函数
x = p.x;
y = p.y;
count++;
}
~Point(){
count--;}
int getX(){
return x;}
int getY(){
return y;}
static void showCount(){
// 输出静态数据成员
cout << " Object count = " << count << endl;
}
private: // 私有数据成员
int x,y;
static int count; // 静态数据成员的声明,用于记录点的个数
};
int Point::count = 0; // 静态数据成员定义和初始化,使用类名限定
int main(){
Point a(4,5); // 定义对象a,其构造函数会使count加1
count << "Point A: " << a.getX() << ", " << a.getY();
Point::showCount(); // 输出对象个数 也可以通过a.showCount(); 来调用静态成员函数
Point(a); // 定义对象b,其拷贝构造函数会使count增1
cout << "Point B: " << b.getX() << ", " << b.getY();
Point::showCount(); // 输出对象个数
return 0;
}
数据封装
和数据隐藏
的机制。为了确保数据的完整性,及数据封装与隐藏的原则,建议尽量不使用或少使用友元。
友元函数
是在类声明中由关键字friend
修饰说明的非成员函数,在它的函数体中能够通过对象名访问 private
和 protected
成员作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。
友元函数
访问对象中的成员必须通过对象名
。示例: 使用友元函数计算两点间的距离
#include
#include
using namespace std;
class Point {
//Point类声明
public: //外部接口
Point(int x=0, int y=0) : x(x), y(y) {
}
int getX() {
return x; }
int getY() {
return y; }
friend float dist(Point &a, Point &b); // 友元函数
private: //私有数据成员
int x, y;
};
float dist( Point& a, Point& b) {
double x = a.x - b.x;
double y = a.y - b.y;
return static_cast<float>(sqrt(x * x + y * y));
}
int main() {
Point p1(1, 1), p2(4, 5);
cout <<"The distance is: ";
cout << dist(p1, p2) << endl;
return 0;
}
声明语法:将友元类名在另一个类中使用friend
修饰说明。
class A {
friend class B; // 类中友元函数的声明可以放在任何地方,不受public、protected和private的管辖和限制
public:
void display() {
cout << x << endl;
}
private:
int x;
};
class B {
public:
void set(int i);
void display();
private:
A a; // 注意被声明为友元类的类,要通过被访问类的对象进行访问该类的成员变量和成员函数
};
void B::set(int i) {
a.x=i;
}
void B::display() {
a.display();
};
注意:类的友元关系是单向的
const
进行修饰)。对于不改变对象状态的成员函数应该声明为常函数。
const 类名 对象名
或类名 const 对象名
const
进行修饰的类成员:
常数据成员
常函数成员
:不更新对象的数据成员
类型说明符 函数名(参数表)const;
这里,const
是函数类型的一个组成部分,因此在实现部分也要带const
关键字。const 类型说明符 &引用名
类型说明符 const 数组名[大小]...
class A{
public:
A(int i,int j) {
x=i; y=j;}
...
private:
int x,y;
};
A const a(3,4); //a是常对象,不能被更新
#include
using namespace std;
class R {
public:
R(int r1, int r2) : r1(r1), r2(r2) {
}
void print();
void print() const; // 常成员函数声明
private:
int r1, r2;
};
void R::print() {
cout << r1 << ":" << r2 << endl;
}
void R::print() const {
cout << r1 << ";" << r2 << endl;
}
int main() {
R a(5,4);
a.print(); //调用void print()
const R b(20,52);
b.print(); //调用void print() const
return 0;
}
为什么要在构造函数中完成对常数据成员的初始化赋值操作?
因为常数据成员只能赋值一次,当对象被创建时,会自动调用构造函数,对成员数据进行赋初值,如果不指定,通常被赋值为0,而0不一定时我们想要的数值。
#include
using namespace std;
class A {
public:
A(int i);
void print();
private:
const int a;
static const int b; //静态常数据成员,必须在类外定义和初始化,且类外定义不能有static关键字
};
const int A::b=10; // 静态数据成员的定义和初始化
// 注意***********************************************
// 只能通过构造函数的 参数初始化列表 对常数据成员进行初始化。不能采用在构造函数的函数体中对常数据成员赋初值的方法
A::A(int i) : a(i) {
} // 通过构造函数初始化常数据成员,且只能在初始化列表中初始化,不能在构造函数的函数体中初始化赋值
void A::print() {
cout << a << ":" << b <<endl;
}
int main() {
//建立对象a和b,并以100和0作为初值,分别调用构造函数,
//通过构造函数的 初始化列表 给对象的 常数据成员 赋初值
A a1(100), a2(0);
a1.print();
a2.print();
return 0;
}
常引用作形参
#include
#include
using namespace std;
class Point {
//Point类定义
public: //外部接口
Point(int x = 0, int y = 0): x(x), y(y) {
}
int getX() {
return x; }
int getY() {
return y; }
friend float dist(const Point &p1,const Point &p2); // 这样的友元函数创建,会使得当前类更安全
private: //私有数据成员
int x, y;
};
float dist(const Point &p1, const Point &p2) {
double x = p1.x - p2.x;
double y = p1.y - p2.y;
return static_cast<float>(sqrt(x*x+y*y));
}
int main() {
//主函数
const Point myp1(1, 1), myp2(4, 5);
cout << "The distance is: ";
cout << dist(myp1, myp2) << endl;
return 0;
}
如何理解初始化列表???
声明
和定义
是两码事,声明
仅仅是给编译器作提示用,定义
是编译器实实在在地把内容转换成二进制代码,分配内存空间,作为可执行的特定指令。所以声明可以有多处,但是同一内容却只能定义
一次以避免定义二义性和模糊性。用extern
就是明确告诉编译器这是在声明
,而不是定义
。
对于函数的声明
,加不加extern
都行,因为函数的声明后面会跟一个分号,很容易辨识。但是,基本变量的定义和声明在不加extern时,都会被对待为定义,所以要想使用其他文件的全局变量,必须在引用的文件中用extern
声明。
extern
修饰,其效果与不加修饰的默认状态是一样的。将变量和函数限制在编译单元内
namespace{
// 被namespace{...}括起来的区域都属于匿名的命名空间。
int n;
void f(){
n++;
}
}