类与对象
对象(Object)
- 代表失误、事件、概念
- 对象在运行过程中相互发送消息
类(class)
- 定义实例的属性
- 在C++中就是类型
OOP特性
- 所有事物都是对象
- 程序由一串对象组成,对象之间通过发送消息告诉其他对象应该做什么
- 每一个对象都有它自己的内存,内存中又由其他对象组成
- 任何对象都有一个类型
- 一个特点类型的所有对象都能接收同样的消息
对象的接口
- 接口是接收消息的方式
- 由对象所属的类定义
VS添加一个新类
VS:项目->添加类->类名->确定
class A
{
public:
A(int i);
~A();
};
类访问修饰符
- public: 公有成员
公有成员在程序中类的外部是可访问的。您可以不使用任何成员函数来设置和获取公有变量的值
- protected: 受保护成员
私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
- private: 私有成员
保护成员变量或函数与私有成员十分相似,但有一点不同,保护成员在派生类(即子类)中是可访问的。
构造函数与析构函数
- 构造函数:
类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。
构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。
默认的构造函数没有任何参数,但如果需要,构造函数也可以带有参数。这样在创建对象时就会给对象赋初始值,使用初始化列表来初始化字段
构造函数不能主动调用
- 析构函数:
类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。
析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。
拷贝构造函数
class Line
{
public:
int getLength( void );
Line( int len ); // 简单的构造函数
Line( const Line &obj); // 拷贝构造函数
~Line(); // 析构函数
private:
int *ptr;
};
构造函数中使用const 类 的引用来初始化对象,是成员变量对成员变量的拷贝。如果没有定义拷贝构造函数,C++会自动给一个拷贝构造
- 通过使用另一个同类型的对象来初始化新创建的对象。
- 复制对象把它作为参数传递给函数。
- 复制对象,并从函数返回这个对象。
隐藏的拷贝构造
void roster(Person);
Person child("Ruby");
roster(child);
动态内存分配
new与delete
new是在程序运行时分配内存的方法。指针成为对内存的唯一访问方式。delete回收内存
int * psome = new int [10];
delete [] psome;
使用new int[10] 方式申请的内存,需要用delete[] p 方式释放。否则只会释放内存但不会调用除p[0]以外的析构函数
继承
当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。
声明方式如下:
class derived-class: access-specifier base-class
如果父类构造函数由参数,子类在构造函数中要给出initialization。
class Q
{
public:
Q(int i) {} // 带参数的构造函数
~Q() {}
void set(int i) { this->i = i; }
virtual void print() { cout << "print() Q " << endl;}
void print(int ii) { cout << "print(int ii ) " << endl;} // overload函数,参数表不同,不是同一个函数
private:
int i;
int Price;
int Banlance;
int Tatal;
};
class Qsub : public Q
{
public:
int temp;
Qsub():Q(11),temp(10) {} // 构造函数列表 给出基本的初始化,temp参数的初始化列表
void fun() { set(20); }
void print() { cout << "print() Qsub " << endl;} // c++ 中子类和父类名字参数都相同的函数之间没有关系,使用子类print时会把父类print()函数隐藏
};
void printTest(Q * p) // 向上造型,派生类以基类的方式看待,有virtual就是动态绑定
{ // 这里p就是多态性
p->printf();
}
int main()
{
Q obja;
Qsub objb;
printTest(&obja);
printTest(&objb); // 如果基类print() 有virtual修饰,会找到objb的print()函数来运行
return 0;
}
多态
class XYPos {}; // x,y point
class Shape {
public:
Shape();
virtual ~Shape();
virtual void render();
void move(const XYPos&);
virtual void resize();
protected:
XYPos center;
};
class Ellipse : public Shape {
public:
Ellipse(float maj, float minr);
virtual void render(); // will define own
protected:
float major_axis, minor_axis;
};
class Circle : public Ellipse {
public:
Circle(float radius) : Ellipse(radius, radius) {}
virtual void render();
};
Shape有三个虚函数:析构函数destractor()、render()、resize()
构成override关系
引用
char c;
char &r = c;
引用,存放的对象的另一个名字。
class A{
int& x;
A(int& i) {}
};
A::A(int& i):x(i) {}
void fun(const A& a){}
引用作为类的成员时,类的成员不带初始化,因此必须在定义对象时候的构造函数的初始化列表项中初始化引用。
给函数传参时使用。传递一个对象的时候。
int& func() {
int q;
//! return q; // 在编译时发生错误
static int x;
return x; // 安全,x 在函数作用域外依然是有效的
}
当返回一个引用时,要注意被引用的对象不能超出作用域。所以返回一个对局部变量的引用是不合法的,但是,可以返回一个对静态变量的引用。C语言中也一样,返回类型为指针时,不能返回局部变量的指针。
(VS中编译居然能通过??)