目录
- 1、用类创建对象
- 1、面向对象的特征
- 2、对象由什么构成
- 3、如何定义对象
- 4、创建对象并访问对象成员
- 1. Constructors(构造函数)
- 2. Constructing Objects (创建对象)
- 3. Object Member Access Operator(对象访问运算符)
- 2、对象拷贝以及分离声明与实现
- 1、类是一种数据类型
- 1.1. 定义变量的例子:
- 1.2. 定义对象的例子:
- 2. Memberwise Copy (成员拷贝)
- 3、匿名对象
- 4、局部类和嵌套类
- 5、question-是否存在匿名对象?
- 3、Separating Declaration from Implementation
- 1、C中的用法
- 2、Separating Declaration from Implementation
- 3、Inline Declaration & Inline Function
- 4、注意事项
- 4、避免头文件被多次包含
1、用类创建对象
1、面向对象的特征
(1) Abstraction (抽象)
(2) Polymorphism (多态)
(3) Inheritance (继承)
(4) Encapsulation (封装)
2、对象由什么构成
对象具有唯一的标识、状态和行为。
对象状态由数据域(也称为“属性”)及其当前值构成。
对象的行为由一组函数定义。
3、如何定义对象
对象是类的实例。
类包含:
1、由变量定义的数据域
2、由函数定义的行为
类中有两种特殊的函数:
constructors : (构造函数:在创建对象时被自动调用)
destructors : (析构函数:在对象被销毁时被自动调用)
4、创建对象并访问对象成员
1. Constructors(构造函数)
class Circle {
public:// The radius of this circledouble radius;// Construct a circle objectCircle() {radius = 1;}// Construct a circle objectCircle(double newRadius) {radius = newRadius;}// Return the area of this circledouble getArea() {return radius * radius * 3.14159;}
};
Ctors的特点:
(1) Automatic invocation(自动调用)
(2) Has the same name as the defining class (与类同名)
(3) NO return value (including “void”);(无返回值)
(4) Can be overloaded (可重载)
(5) May have no arguments (可不带参数)
类可不声明构造函数,编译器会提供一个带有空函数体的无参构造函数,只有当未明确声明构造函数时,编译器才会提供这个构造函数,并称之为“默认构造函数”。
2. Constructing Objects (创建对象)
Circle circle1; // 正确,但不推荐这样写
Circle circle2(); // 错误!C++编译器认为这是一个函数声明
Circle circle3{}; // 正确,推荐写法。这里面明确显示用空初始化列表初始化circle3对象(调用Circle默认构造函数)Circle circle2{ 5.5 }; // C++11 列表初始化// 带有窄化检查(narrowing check)
3. Object Member Access Operator(对象访问运算符)
#include <iostream>
using namespace std;
class Circle {
public:// The radius of this circledouble radius;// Construct a circle objectCircle() {radius = 1;}// Construct a circle objectCircle(double newRadius) {radius = newRadius;}// Return the area of this circledouble getArea() {return radius * radius * 3.14159;}
};int main() {Circle circle1;Circle circle2(5.0);cout << "The area of the circle of radius " <<circle1.radius << " is " << circle1.getArea() << endl;cout << "The area of the circle of radius " <<circle2.radius << " is " << circle2.getArea() << endl;// Modify circle radiuscircle2.radius = 100.0;cout << "The area of the circle of radius " <<circle2.radius << " is " << circle2.getArea() << endl;return 0;
}
2、对象拷贝以及分离声明与实现
用类声明一个实体的说法,与定义变量的说法有些不同:用原生数据类型定义变量,用类名定义对象。
1、类是一种数据类型
1.1. 定义变量的例子:
// primitive data type è variablesdouble d1; //未初始化double d2(3.3); int x1{2.0}; //error: Narrowingint x2={4};auto i{x};decltype(d1) j;
1.2. 定义对象的例子:
// class è objectsCircle c1; //调用Circle的默认ctorCircle c2(5.5); //调用Circle的有参ctorCircle c3{5.5}; // 直接列表初始化,调有参ctorCircle c4 = {5.5}; // 拷贝列表初始化,调ctorauto c5 = Circle{2.}; // auto类型推断decltype(c1) c6; // decltype类型推断
2. Memberwise Copy (成员拷贝)
1、使用赋值运算符: =
2、默认情况下,对象中的每个数据域都被拷贝到另一对象的对应部分
circle2 = circle1;
(1) 将circle1 的radius 拷贝到circle2 中
(2) 拷贝后:circle1 和 circle2 是两个不同的对象,但是半径的值是相同的。( 但是各自有一个radius 成员变量)
3、匿名对象
Occasionally, you may create an object and use it only once. (有时需要创建一个只用一次的对象)
An object without name is called anonymous objects. (这种不命名的对象叫做匿名对象)
Example
int main() {Circle c1 = Circle{1.1};auto c2 = Circle{2.2}; // 用匿名对象做拷贝列表初始化Circle c3{}; // 直接列表初始化,调默认Ctorc3 = Circle{3.3}; // 用匿名对象赋值cout << "Area is " << Circle{4.2}.getArea() << endl;cout << "Area is " << Circle().getArea() << endl; // 不推荐cout << "Area is " << Circle(5).getArea() << endl; // 不推荐return 0;
}
4、局部类和嵌套类
Local class : a class declared inside a function (局部类是在一个函数中声明的类)
void f(){class C { // C及其对象只在f()中可用 void g() { // 成员函数必须在C中实现/* 访问f()的成员受限 ……. */}};C c1, c2;
}
Nested class: a class declared in another enclosing class (嵌套类是在另一个类中声明的类)
class E{class N { // N及其对象可访问E的成员 /* 声明N的成员 ……. */}};C c1, c2;}
5、question-是否存在匿名对象?
question description:
Circle类接受一个double参数构造其对象,那么
Circle c1 = { 1.0 };
Circle c2 = Circle {1.0};
这两条语句的执行结果是相同的,c1和c2都是一个半径为1.0的圆对象。
但是,这两条语句执行过程是否一样呢?第一条语句的等号右侧是否也构造了一个匿名对象呢?
两者的执行结果是一样的,都是将c1和c2对象的半径赋值1.0。
但是执行过程是不一样的,c1是通过拷贝列表初始化的方式赋值;c2是通过匿名对象拷贝的方式赋值。
3、Separating Declaration from Implementation
在声明之后,定义之前,类为不完整类型,只能用于指向该类型的指针或者引用或者
用于声明使用该类型作为形参类型或者返回类型的函数。
解决方法:
1、将函数的实现放在类声明的最下面
2、将类的声明放在一个头文件中,类的实现放在另一个文件中。
1、C中的用法
// GetArea.h:
float getArea (float radius);// GetArea.cpp:
#include "GetArea.h"
float getArea (float radius) {return radius*radius*3.14;
}
//main.c:
#include "GetArea.h"
int main() {int result=getArea(2.0;return 0;
}
2、Separating Declaration from Implementation
(1) .h: 类声明,描述类的结构
(2) .cpp: 类实现,描述类方法的实现
FunctionType ClassName :: FunctionName (Arguments) { //… }
其中,:: 这个运算符被称为binary scope resolution operator(二元作用域解析运算符),简称“域分隔符”
Circle.h
//Circle.h
class Circle{double radius;
public:Circle();Circle(double radius_);double getArea();
};
Circle.cpp
Circle::Circle(){radius=1.0;
}
Circle::Circle(double radius_){radius=radius_;
}
double Circle::getArea(){return (3.14 * radius * radius);
}
main.cpp
//main.cpp
int main(){Circle c1;Circle c2 {2.0};std::cout << c1.getArea() << std::endl;return 0;
}
3、Inline Declaration & Inline Function
1、当函数在类声明中实现,它自动成为内联函数
class A {
public:A() = default; //C++11,编译器识别后一定会生成一个默认的构造函数double f1() { // f1自动称为内联函数// do something} double f2();
};
double A::f2() { // f2不是内联函数//do something}
2、当函数在类的外部实现,加上inline也会成为内联函数
class A {
public:A() = default; //C++11double f1();double f2();
};
double A::f2() {//do something
}
inline double A::f1() { // f1是内联函数//do something
}
4、注意事项
1. //a.h
2. void f();
3.
4. // a.cpp
5. #include "a.h"
6. void f() {}
7.
8. //main.cpp
9. #include "a.h"
10. void f() {}
第6行和第10行构成了语法错误:重定义函数
但是 Compiler 不报错,这个错误只能在link阶段才能检测出来。
4、避免头文件被多次包含
例1:
#ifndef MY_HEADER_FILE_H#define MY_HEADER_FILE_H// 头文件内容#endif
例2:
#pragma once // C++03, C90
例3
_Pragma("once") // C++11, C99; _Pragma是一个运算符