c++ 零碎知识点
vitual 理解
1.虚函数 - (多态的一种方式)
可以在基类中将被重写的成员函数设置为虚函数。
定义: 当通过基类的指针或者引用调用该成员函数时,将根据指针指向的对象类型确定调用的函数,而非指针的类型。
说明
- 只需将基类中的成员内函数声明为虚函数即可,派生类中重写的 virtual 函数自动成为虚函数;
- 基类中的析构函数必须为虚函数, 否则会出现对象释放错误;
- 虚对象的使用将导致类对象占用更大的内存空间;
- 重写函数的特征标(包括参数的数目、类型和顺序)必须与基类函数一致,否则将覆盖基类函数;
- 重写不等于重载。
2. 虚基类
虚基类可以使得从多个类(他们继承自一个类)中派生出的对象只继承衣蛾对象。写法如下:
class mytest:vitual public base
{
};
3. 纯虚函数
纯虚函数只是提供了一个可被子类型改写的接口。本身并不能通过虚拟机制被调用。写法如下:
class Query {
public:
// 声明纯虚拟函数
virtual ostream& print( ostream&=cout ) const = 0;
// ..
};
函数声明后面紧跟赋值0。
包含一个或多个纯虚拟函数的类被编译器识别为抽象基类。抽象基类不能被实例化,一般用于继承。
friend 理解
友元机制允许类的非公有成员被一个类或者函数访问,友元类型分为三种:
普通非类成员函数作为友元,
类的成员函数作为友元,
类作为友元。
友元包括友元的声明以及友元的定义。友元的声明默认了 extern, 就是说友元类或者友元函数的作用域已经扩展到了包含该类定义的作用域,所以即便我们在类的内部定义友元函数也是没有关系的。
友元是一种定义在类外部的普通函数,但它需要在类体内进行说明。
友元不是成员函数,但是它可以访问类中的私有成员。类的作用在于提高程序的运行效率(即减少了类型检查和安全性检查等都需要的时间开销),但是,它破坏了类的封装性和隐藏性,是的非成员你函数可以访问类的私有成员。
普通的非成员函数友元
#include "cmath"
#include "iostream"
using namespace std;
class Point
{
public:
Point(double xx, double yy)
{
x = xx;
y = yy;
}
void GetXY();
friend double Distance(Point &a, Point &b);
protected:
private:
double x, y;
}
void Point::GetXY()
{
cout << "(" << x << "," << y << ")" << endl;
}
double Distance(Point &a, Point &b)
{
double length;
length = sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); // 它可以引用类中的私有成员
return length;
}
int main(void)
{
Point p1(3.0, 4.0), p2(6.0, 8.0);
p1.GetXY(); // 成员函数的调用方法, 通过使用对象来调用
p2.GetXY();
double d = Distance(p1, p2); // 友元函数的调用方法,同普通函数的调用一样, 不要像成员函数那样调用
cout << d << endl;
system("pause");
return 0;
}
类作为友元
类作为友元需要注意的是友元类和原始类之间的相互依赖关系, 如果在友元类中定义的函数使用到了原始类的私有变量,那么就需要在友元类定义的文件中包含原始类定义的文件。但是在原始类的定义中(包含友元类声明的那个类), 就不需要包含友元类的头文件。
不需要在类定义前去声明友元类, 因为友元类的声明自身就是一种声明。
// A.h
#pragma once
#include <iostream>
using namespace std;
class A
{
friend class B; // 如果不屑这句话将会出现编译错误
public:
~A(void);
A();
private:
int m_nItem;
};
// A.cpp
#include "A.h"
A::A()
{
m_nItem = 3;
}
A::~A(void)
{
}
// B.h
#pragma once
class B
{
public:
B(void);
~B(void);
int func();
};
//B.cpp
#include "StdAfx.h"
#include "B.h"
#include "A.h" // must include A.h
#include <iostram>
B::B(void)
{
}
B::~B(void)
{
}
int B::func()
{
cout<< "This is in B" << endl;
A a;
return a.m_nItem;
}
友元函数的使用技巧
在用 C++ 实现单例模式时,可以利用友元函数实例化对象。然后把类的构造函数和析构函数都涉及成私有函数。
class CMySingleton
{
public:
friend CMySingleton& InstanceMEC();
private:
CMySingleton() {};
CMySingleton(const CMySingleton &lxSingleton) {};
~CMySingleton() {};
};
CMySingleton& InstanceMEC()
{
// 因为函数 InstanceMEC() 是类 ClxSingletonMEC 的友元函数, 所以可以访问类所有的成员函数
static CMySingleton Instancec;
return Instance;
}
static 理解
总结
当 static 作用于非类函数的局部变量时, 每次函数调用不会随着函数返回而失效, 当 static 作用于类内成员时, 由该类所有对象共同维护和使用, 从而实现同一个类的不同对象数据共享。
作用域函数内部的局部变量
局部作用域静态变量的特点: 当一个函数返回后, 下一个函数返回后, 下一次再调用时, 该变量还会保持上一回的值, 函数内部的静态变量只会开辟一次空间, 且不会因为多次调用产生副本, 也不会因为函数返回而失效。
#include <iostream>
using namespace std;
void fun()
{
static int count = 0; // static 作用的静态变量
count++;
cout << "count=" << count << endl;
}
int main()
{
cout << "calling the "fun()" for the first time! " << endl;
fun();
cout << "calling the "fun()" for the second time! " << endl;
fun();
return 0;
}
运行结果如下:
calling the "fun()" for the first time!
count=1
calling the "fun()" for the second time!
count=2
作用于类的成员, 解决同一个类的不同对象之间数据和函数共享问题
作用于类的成员, 使其成为静态数据成员
静态成员再每一个类中只有一个副本, 由该类所有对象共同维护和使用, 从而实现同一个类的不同对象数据共享。
需要注意的是:
访问静态数据成员方式: 类名::标识符
对静态数据成员初始化: 在类定义外进行
#include <iostream>
using namespace std;
class Point
{
public:
Point(int x = 0, int y = 0) : x(x), y(y)
{
count++;
}
Point(Point &p)
{
x = p.x;
y = p.y;
count++;
}
virtual ~Point() { count--; }
int getX() { return x; }
int getY() { return y; }
void showCount() /* 输出静态数据成员 */
{
count << "Object count = " << count << endl;
}
private:
int x, y;
static int count; /* 静态数据成员声明, 用于记录点的个数 */
}
int Point::count = 0; /* 静态数据成员定义和初始化, 使用类名限定 */
int main()
{
Point a(4, 5);
cout << "Point A:" << a.getX() << "," << a.getY();
a.showCount(); /* 输出对象个数 */
Point b(a);
cout << "Point B:" << b.getX() << "," << b.getY();
b.showCount(); /* 输出对象个数 */
cout << "Point B:" << b.getX() << "," << b.getY();
a.showCount(); /* 输出对象个数 */
return 0;
}
运行结果如下:
Point A: 4, 5 Object count = 1
Point B: 4, 5 Object count = 2
Point A: 4, 5 Object count = 2
该运行结果清晰的显示了同一个类的不同对象数据共享的理解。
作用于类的函数成员, 使其成为静态函数成员
静态成员函数就是使用 static 关键字声明的函数成员, 同静态数据成员一样, 静态成员函数也属于整个类, 由该类所有对象共同所有, 为所有对象共享。
- 静态成员主要用于处理该类的静态数据成员, 可以直接调用静态数据成员。如果访问非静态成员, 要通过对象来访问。
class A
{
public:
static void f(A a);
private:
int x;
static int y;
}
void A::f(A a)
{
cout << x; /* 对 x 的引用是错误的 */
cout << a.x; /* 正确 */
cout << y; /* 对 x 的引用时正确的, 引用静态数据成员 */
}
- 如果想在类外调用静态成员函数呢? ------类外代码一般使用类名和作用域操作符来调用静态成员函数
访问方式: 一般通过类名::函数名调用, 也可用类.函数名调用
#include <iostream>
using namespace std;
class Point
{
public:
Point(int x = 0, int y = 0) : x(x), y(y)
{
count++;
}
Point(Point &p)
{
x = p.x;
y = p.y;
count++;
}
virtual ~Point() { count--; }
int getX() { return x; }
int getY() { return y; }
static void showCount() /* 输出静态数据成员 */
{
count << "Object count = " << count << endl;
}
private:
int x, y;
static int count; /* 静态数据成员声明, 用于记录点的个数 */
}
int Point::count = 0;
int main()
{
Point::showCount(); /* 静态成员函数可通过类名::函数名调用 */
Point a(4, 5);
a.showCount(); /* 静态成员你函数也可通过类名::函数名调用 */
return 0;
}