(一)初窥类与对象
1.示例demo
class class_name{
int x = 0;
public:
class_name();
~class_name();
friend void friendfunc(int x);
int a = 1;
void func();
protcted:
int b = 2;
private:
int c = 3;
};
void class_name::func(void)
{
/*...*/
}
实例化:class_name A; or class_name *class_ptr = new class_name;
从上可以看出一些point:结构、访问权限关键字、成员(属性和方法)、实例化、构造函数与析构函数等。
2.类成员函数
就是定义在类里面的属性和方法;
可以在类定义里面定义,也可以在外部定义,不过一定要指明是那个对象的成员函数,如上func的定义。
3.类访问权限关键字
public、protected、private
使用时如上加:
尤其注意:
(1)类成员都有访问权限,若没有加关键字修饰,则默认为private;
(2)在继承的时候,private、的权限永远不会变,
public继承时,基类的成员权限不变;
protcted继承时,基类的public变为protcted,protected不变。
private时,基类的全部成员权限变为private。
4.构造函数、析构函数,以及不会常用的:拷贝构造函数(主要用于初始化)
构造函数:没有返回值,默认是没有参数的,可以重载为有参数的构造函数,主要执行一些必要的初始化工作。
析构函数:没有返回值,没有参数,主要执行一些清理工作。
5.C++的 类的友元函数
定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。
尽管友元函数的原型有在类的定义中出现过,(声明一个函数为友元函数)但是友元函数并不是类的成员函数。
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。
使用关键字friend。
如在类定义中声明:frind void friendfunc(int x);
在类外部定义:如正常函数般定义。
6.内联函数
就是在一种函数,在被编译的时候代码的副本会被拷贝到调用处,一般短小精悍,类似与一般用define 定义的短小宏。
与类的关联:
当在类定义中定义时,即使不用inline关键字,编译器会默认是内联函数,在类外部的内联函数就必须用到inline修饰类。
7.this指针与指向类的指针
this就是一个指向对象本身的指针,一般在类定义的函数中使用。
指向类的指针:class_name *p = new class_name;
8.类的静态成员
就是成员用static定义后,一个类的所有实例都可以访问,相当于在一个类中全局。
要慎用(在一个类A的实例中修改类该静态成员,则另一个类A的实例去访问这个静态成员,也就被改变类,可以作为一个类间通信机制)。
9.拷贝构造函数
(二)探究面向对象特性之继承
1.继承的含义、基类与派生类(子类)
继承:就是一个类(派生类)通过一种定义方式,获得另一个类(基类)的成员访问
(具体访问权限根据继承类型和基类的成员访问权限共同决定)
2.继承的形式
单继承
class A{
...
};
class B:public/protcted/private A{//class B public/protcted/private(三者之一)继承class A
};
多继承
若class B在定义时要继承多各类,如类C:
class B:public/protcted/private A,public/protcted/private C{
};
多继承需要注意的是:
若A C中都有一个成员a,那么先继承A的a,会忽略C的a。
3.继承的类型及访问权限
访问 public protected private
同一个类 yes yes yes
派生类 yes yes no
外部的类 yes no no
这里还应该注意:
(1)不同的继承类型会决定在派生类中访问基类的权限。
如,基类有public/protcted/private 三种成员,若派生类private继承基类,那么在派生类中,
基类的public/protcted成员在派生类中可以被访问,但是在派生类中变为类private,意味着,这些成员再次被继承时,不能那个被访问。
public与 protected继承同理。
(2)友元函数例外!可以访问与之关联类的所有成员。
几乎不使用 protected private 继承,通常用public 继承。当使用不同类型的继承时,遵循以下几个规则:
公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
4.多重继承
(三)探究面向对象特性之重载与多态
1.重载、多态及其区别
简而言之:
重载就是一个类定义中定义多个函数名相同,参数不同的重载函数(返回值一般是相等的)
注意:不能仅通过返回类型的不同来重载函数。(会编译error)
多态就是在派生类中覆写基类中存在的成员函数。
2.重载就那么回事儿,但是多态就比较有趣了
多态涉及到:虚函数、抽象、接口、模板、泛型编程等概念
3.虚函数 纯虚函数
虚函数就是在类中使用关键字virtual修饰的函数,虚函数是在基类中定义(可以实现,不实现则为纯虚函数),在派生类中覆写。
形如:
class A{
public:
virtual void run(){
this.a = 1;
}
private:
int a;
};
或纯虚函数定义:
class A{
public:
virtual void run()=0; //纯虚函数是通过在声明中使用 "= 0" 来指定的
private:
int a;
};
当派生类B继承A的时候,就可以在派生类中覆写这个虚函数类。
4.多态的覆写分类
(1)基类中被覆写的函数不是虚函数
那么,在使用的时候:
A *a = new B;
a.run(); //虽然实例是B,但是在编译的时候早期(静态)绑定了类A,故调用的是A的run
(2)基类中被覆写的函数不是虚函数
同上例子:a.run(); 将执行B的run,这是后期(动态)绑定
5.抽象 与抽象类
抽象就是说:抽象出功能接口给用户,程序员对其功能接口的实现是封装在幕后的,对用户(服务使用者)是透明的。
当一个类中定义了纯虚函数,那么这个类就是抽象类。
6.特别的:运算符重载
可以重定义或重载大部分 C++ 内置的运算符。这样,就能使用自定义类型的运算符。
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。
与其他函数一样,重载运算符有一个返回类型和一个参数列表。
#include <iostream>
using namespace std;
class Box
{
public:
double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}
void setBreadth( double bre )
{
breadth = bre;
}
void setHeight( double hei )
{
height = hei;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// 程序的主函数
int main( )
{
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
double volume = 0.0; // 把体积存储在该变量中
// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;
// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
return 0;
}
当上面的代码被编译和执行时,它会产生下列结果:
Volume of Box1 : 210
Volume of Box2 : 1560
Volume of Box3 : 5400
例:
// 重载负运算符( - )
Distance operator- ()
{
feet = -feet;
inches = -inches;
return Distance(feet, inches);
}
int main()
{
Distance D1(11, 10), D2(-5, 11);
-D1; // 取相反数
D1.displayDistance(); // 距离 D1
-D2; // 取相反数
D2.displayDistance(); // 距离 D2
return 0;
}
其实这也是多态的一种形式吧,通过重载运算符,使得原本不能作用的对象编成可能。