c与c++
1. 初识OOP
object-oriented paradigm(面向对象编程模型)
面向对象编程的特点:继承和动态绑定,C++通过类的派生支持继承,通过虚拟函数支持动态绑定,虚拟函数提供一种封装体系 实现细节的方法。
术语 | 定义 |
---|---|
抽象(abstraction) | 它是去除对象中不重要的细节的过程,只有那些描述了对象本质特征的关键点才被保留,抽象是一种设计活动,其他概念都是提供抽象的oop特性 |
类(class) | 类是一种用户定义类型,就好像是int这样的内置类型一样,内置类型已经有了一套完善针对他的操作(如:算数运算等),类机制也必须允许程序员规定他所定义的类能够进行的操作。类里面的任何东西被称为类的成员 |
对象(object) | 某个类的一个特定变量,就像j可能是int类型的一个变量一样,对象也可以被称为类的实例(instance) |
封装(encapsulation) | 把类型、数据和函数组合在一起,组成一个类。在C语言中,头文件就是一个非常脆弱的封装实例。它之所以是一个微不足道的封装例子,是因为他的组合形式是纯粹语法意义上的,编译器并不知道头文件是一个语法单位 |
继承(inheritance) | 这是一个很大的概念–允许类从一个更简单的基类中接受数据结构和函数。派生类获得基类的数据和操作,并可以根据需求对他们进行改写,也可以在派生类中增加新的数据和函数成员。在C语言里面不存在继承的概念,没有任何东西何以模拟 |
2. 抽象–取事务的本质
抽象允许程序员实现下列目标
- 隐藏不相关的细节,把注意力集中在本质特性上。
- 向外部世界提供一个"黑盒子"接口。接口确定了施加在对象上的有效操作的集合,但他并不提示对象在内部是怎么实现他们的.
- 把一个复杂系统分解成几个相互独立的组成部分。这个做到分工明确,避免组件之间不符合规则的相互作用。
- 重用和共享代码
3. 封装–把相关的类型、数据和函数组合在一起
4. 展示一些类–用户定义类型享有和预定义类型一样的权限
C++类允许用户自定义类型
- 把用户定义类型和施加在他们上面的操作组合在一起
- 享有和内置类型一样的特权和外观
- 可以用基本的类型创建更复杂的类型
类:用户定义类型加上所有对该类型进行的操作
实现形式:一个包含多个数据的结构,加上这些数据进行操作的函数的指针
5. 访问控制
访问控制是一个关键字,他说明谁可以访问接下来声明的数据或函数
关键字 | 定义 |
---|---|
public | 属于public的声明在类的外部可见,并可以按需要进行设置、调用和操纵。一般原则是不要把累的数据做成public,因为让数据保持私有才符合面向对象编程的理论之一;只有类本省才能改变自己的数据,外部函数只能调用类的成员函数,这就保证累的数据只会以合乎规则的方式被更新 |
protected | 属protected的声明只能由该类本身的函数以及从该类所派生的类的函数使用 |
private | 属private的声明只能被该类的成员函数使用。private声明在类外部是可见(名字是已知的),但是却不能访问 |
friend | 属friend的函数不属于类的成员函数,但是可以向成员函数一样访问类的Private和protect成员,friend可以是一个函数,也可以是一个类 |
virtual | 暂不涉及 |
6. 声明
c++类的声明就是正常的c声明,内容包括函数、类型(包括其他类)或数据,类把他们捆在一起。类中每个函数声明都需要一个实现,他可以在类里面实现,也可以在类的外面实现(通常做法)。
class Fruit{public : peel();slice();juice();
private: int weight, calories_per_oz;};
Fruit melon; //类的一个实例
-
C语言申明:
- 返回值 函数名(参数列表){ /* 实现 */} c++语言声明:
- 返回值 类名::函数名(参数列表){ /* 实现 */}
"::"被称为全局范围分解符
内部实现
class Fruit{public : peel(){printf("in peel");};
slice();juice();
private: int weight, calories_per_oz;};
外部实现
class Fruit{public : peel();slice();juice();
private: int weight, calories_per_oz;};
void Fruit::peel(){printf("in peel");}
以上两种语法等价,第二种更常见,它的好处是可以通过使用头文件,使源代码组织形式更为清晰。第一种通常用于非常简短的函数,他的代码在编译时在声明处自动展开,这样在运行时就不必付出函数调用的代价。
7. 如何调用成员函数
- 在调用成员函数前面附上类的实例名
Fruit melon, orange, banana;
main()
{
melon.slice();
orange.juice();
return 0;
}
- 每个成员函数都有一个this指针参数,它是隐士赋给该函数的,他允许成员函数内部引用自身。
class Fruit{public : peel();;
private: int weight, calories_per_oz;};
void Fruit::peel(){printf("in peel");
this->weight--;
weight--;}
Fruit apple;
printf("address of apple= %x", &apple);
apple.peel();
- 构造函数和析构函数
- 绝大多数类至少具有一个构造函数。当类的一个对象被创建时,构造函数隐式调用
- 与之相对应,类存在一个清理函数,被称为析构函数,当对象被销毁时,析构函数自动调用
C语言中,只能使用赋值符号在变量定义时对他进行初始化,或干脆保持未初始化状态
构造函数总是类的名字是一样的
class Fruit{public : peel();slice();juice();
Fruit(int i, int j); //构造函数
~Fruit(); //析构函数
private: int weight, calories_per_oz;};
// 构造函数体
Fruit::Fruit(int i, int j){weight = i; calories_per_oz = j;};
// 对象声明时由构造函数进行初始化
Fruit melon(4, 5), banena(12, 8)
8. 继承–复用已经定义的操作
从一个类派生另外一个类,使前者所有的特征在后者中自动可用,他可以声明一些类型,这些类型可以共享部分或全部以前所申明的类型。他也可以从超过一个的基类共享一些特征
class Fruit
{
public :
peel();
slice();
juice();
private:
int weight,
calories_per_oz;
};
// 派生类的例子
class Apple:public Fruit
{
Public :
void make_candy_apple(float weight);
void bob_for(int tun_id, int number_of_attempts);
};
// 对象声明的例子
apple teachers;
9. 多重继承–从两个或更多的基类派生
10. 重载–作用于不同类型的同一操作具有相同的名字
重载:简单的复用一个现存的名字,但使她操作一个不同类型。他可以是函数的名字,也可以是一个操作符。
11. C++如何进行操作符重载
class Fruit{public : peel();slice();juice();
int operator+(Fruit &f); //重载“+”操作符
private: int weight, calories_per_oz;};
// 重载“+”操作符函数体
int Fruit::operator+(Fruit &f)
{
printf("calling fruit addition\n")
return weight + f.weight;
}
// 调用
Apple apple;
Fruit orange;
int ounces = apple + orange;
12. c++的输入输出
C++有一个iostream.h头文件,提供I/O接口,使I/O操作更为方便,符合OOP理念
c++ 使用<<操作符(输出,或称“插入”)和>>操作符(输入,或称“提取”)来代替C语言中的putchar()和getchar()函数
cout << "the value is " << i << endl;
13. 多态–运行时绑定
多态:一个函数或者操作符只有一个名字,但是他可以用于几个不同的派生类型的能力。每个对象都实现该操作的一种变型,变现一种最适合自身的行为。
class Fruit
{
public :
peel() {printf("peeling a base class fruit\n");}
slice();
juice();
private:
int weight,
calories_per_oz;
};
//声明和调用
Fruit banana;
banana.peel();
//输出一个消息
peeling a base class fruit
class Apple :public Fruit
{
public :
void peel(){printf("peeling an apple\n");}
void make_candy_apple(float weight);
};
//声明和调用
fruit *p;
p = new apple;
p->peel();
peeling a base class fruit
14. 解释
出现上面这个结果的原因是:当派生类的成员函数取代基类的同名函数时,c++要求你必须预先通知编译器。通知的方法就是在可能被取代的基类成员函数面前加上virtual关键字
15. c++如何表现多态
#include "stdio.h"
class Fruit
{
public:
virtual void peel()
{
printf("peeling a base fruit\n");
}
private:
int weight, calories_per_oz;
};
class Apple: public Fruit
{
public :
void peel()
{
printf("peeling an apple\n");
}
};
int main()
{
Fruit *fruit = new Apple;
fruit->peel();
}
运行结果:peeling an apple
结果可以在编译是获得,多态是一种运行时效果。它是指c++对象在运行时决定应该调用那个函数来实现某个特定操作的过程。
16. 多态
#include "stdio.h"
class Fruit
{
public:
virtual void peel()
{
printf("peeling a base fruit\n");
}
private:
int weight, calories_per_oz;
};
class Apple: public Fruit
{
public :
void peel()
{
printf("peeling an apple\n");
}
};
int main()
{
Apple apple;
Fruit fruit;
Fruit *p;
p = &fruit;
p->peel();
p = &apple;
p->peel();
}
运行结果:
peeling a base fruit
peeling an apple