以下内容为本人学习笔记,不足之处请指出,后期会不断完善。
#访问权限:
- public 公共接口 :向外界开放,可通过对象或类名访问
- protected 受保护的访问:类内可以访问 ,不可通过对象访问,可以被派生类访问,不能被用户代码(类外)访问。主要作用是来实现类的一个特征就是继承
- private私有 :只能由类成员(类内)和友元访问,外界不可以通过任何形式访问
#继承关系: - public继承是is-a的关系,可以用父类的指针或者引用指向子类的对象,适用于基类身上的每一件事情一定适用于派生类身上,因为每一个派生对象也都是基类对象;
- protected和private继承没有is-a的关系,只是has-a的关系,表示“组合”或者“拥有”的关系,不可以用父类的指针或引用指向子类对象。
- C++对象模型中,子类对象的内存空间中包含父类的部分,当用父类指针指向一个子类的对象实时,这个指针可以访问的是相应的父类那部分的内存;在 protected和private继承的情况下,父类的内存部分是私有的,不对外开放的,所以,protected和private继承时,不可以用父类的指针或引用指向子类对象。
#类的静态数据成员
- 使用static关键字声明
- 为该类的所有对象共享,静态数据成员具有静态生存期。
- 必须在类外定义和初始化,用(::)来指明所属的类。
例子:
#include <iostream>
using namespace std;
class Point{
public :
Point(int x=0,int y=0):x(x),y(x){//构造函数
count++;
}
Point(Point &p){//复制构造函数
x=p.x;
y=p.y;
count++;
}
~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 Ponit::count = 0;//静态数据成员定义与初始化
int main(){
Point a(4,5);
cout <<"Point A:"<<a.getX()<<","<<a.getY()<<endl;
a.showCount();
Point b(a);
cout <<"Point B:"<<b.getX()<<","<<b.getY()<<endl;
b.showCount();
return 0;
}
输出结果:
Point A:4,5 Object count=1
Point B:4,5 Object count=2
数据保护
常类型
常对象
- 必须进行初始化,不能被更新。
- 定义:类名 const 对象名(实参列表);或 const 类名 对象名(实参列表);
- 如果一个对象被声明为常对象,则不能调用该对象的非const型的成员函数(除了由系统自动调用的隐式构造函数和析构函数)。否则就会报错。
常成员
- 用const进行修饰的类成员:常数据成员(只能通过构造函数的参数初始化表对常数据成员进行初始化)和常函数成员(专门用来处理常对象的,声明和定义处都要写const)。
例子:常数据成员
#include <iostream>
using namespace std;
class A{
public :
A(int i);
void print();
private:
const int a;
static const int b;//静态常成员函数(类中是共享的)
};
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
}
运行结果:
100:10
0:10
例子:常函数成员
#include <iostream>
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::printf(){
cout<<r1<<":"<<r2<<endl;
}
void R::printf() const {
cout<<r1<<":"<<r2<<endl;
}
int main(){
R a(4,5);
a.print();//void print()
const R b(20,54);
b.print();//void print() const
return 0;
}
常引用
- 被引用的对象不能被更新,不能修改。
- 定义 const 类型说明符 &引用名;
例子:
#include <iostream>
#include <cmath>
class Point{
public :
Point(int x=0,int y=0):x(x),y(x){}
int getX(){return x;}
int getY(){return y;}
friend float dist(const Point &a,const Point &b);
private:
int x,y;
};
float dist(const Point &a,const Point &b){
double x=a.x-b.x;
double y=a.y-b.y;
float static_cast<float>(sqrt(x*x+y*y));
}
int main(){
Point p1(1,1),p2(3,5);
cout <<dist(p1,p2)<<endl;
}
常数组
- 数组元素不能被更新。
- 定义: 类型说明符 const 数组名[大小];
常指针
- 指向常量的指针。
类的友元
- 友元是C++提供的一种破坏数据封装和数据隐藏的机制。
- 通过将一个模块声明为另一个模块的友元,一个模块能够引用到另一个模块中本是被隐藏的信息。
- 可以声明友元函数和友元类
- 为了确保数据的完整性,及数据封装与隐藏的原则,建议慎用友元。
友元函数
- 友元函数是在类声明中由关键字friend修怖说明的非成员函数,在它的函数体中能够通过对象名访问private和protected成员,
- 作用:增加灵活性,使程序员可以在封装和快速性方面做合理选择。
- 访问对象中的成员必须通过对象名。
#include <iostream>
#include <cmath>
class Point{
public :
Point(int x=0,int y=0):x(x),y(x){}
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;
float static_cast<float>(sqrt(x*x+y*y));
}
int main(){
Point p1(1,1),p2(3,5);
cout <<dist(p1,p2)<<endl;
}
友元类
- 若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。
- 声明语法:将友元类名在另一个类中使用friend修饰说明。
例如:
class A {
friend class B;
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();
}
例子2:
class Point{
class Point{
public :
Point(int x=0,int y=0):x(x),y(x){}
int getX(){return x;}
int getY(){return y;}
friend QDebug& operator<<(Qdebug &debug,const Point &point);//运算操作符重载
private:
int x,y;
}
QDebug& operator<<(Qdebug &debug,const Point &point){
return debug<<Qsting("[%1,%2]").arg(point.x).arg(point.y);
}
int main(){
Qapplication app(argc,argv);
Qlist<Point> points;
points<<Point(1,2)<<Point(2,3);
qDebug<<points;
return 0;
}
多态性
实现类动态多态性,需要声明函数为虚函数,这样就可以实现使用基类指针来访问不同的派生类实例函数。
#include <iostream>
using namespace std ;
class Basel {
public:
virtual void display() const; //虚函数
};
void Basel::display() const {
cout << "Basel: display()" << endl
}
class Base2::public Base1 {
public:
virtual void display() const; //虚函数
};
void Base2::display() const {
cout << "Base2: display()" << endl
}
class Derived::public Base2 {
public:
virtual void display() const; //虚函数
};
void Derived::display() const {
cout << "Derived: display()" << endl
}
void fun(Base1 *ptr){
ptr->display();
}
int main(){
Base1 base1;
Base2 base2;
Derived derived;
fun(&base1);
fun(&base2;
fun(&derived);
return 0;
}
运行结果为:
Basel: display()
Base2: display()
Derived: display()
这样就达到了使用基类指针访问进程类函数的目的,如果不添加虚函数,则运行的结果为:
Basel: display()
Basel: display()
Basel: display()
纯虚函数
- 纯虚函数是一个在基类中声明的虚函数,它在该基类中没有定文具体的操作内容,要求各派生类根据实际需要定义自己的版本,纯虚函数的声明格式为:
- 定义: virtual 函数类型 函数名(参数表)=0;
抽象类:
- 定义
class 类名{
virtual 函数类型 函数名(参数表)=0;
//其他成员。。。
}
- 抽象类作用
- 将有关的数据和行为组织在一个继承层次结构中,保证派生类具有要求的行为。
- 对于暂时无法实现的函数,可以声明为纯虚函数,留给派生类去实现。
- 注意
抽象类只能作为基类来使用,不能定义抽象类的对象。