CPP05 Classes and Objects

本文深入讲解面向对象编程的核心概念,包括对象、类、抽象、封装、继承与多态。通过实例展示如何使用C++创建类与对象,以及如何实现封装以保护数据安全。

What is an Object?

Object Oriented Programming is a programming style that is intended to make thinking about programming closer to thinking about the real world.

In programming, objects are independent units, and each has its own identity, just as objects in the real world do.

An apple is an object; so is a mug. Each has its unique identity. It’s possible to have two mugs that look identical, but they are still separate, unique objects.

Objects

An object might contain other objects but they’re still different objects.

Objects also have characteristics that are used to describe them. For example, a car can be red or blue, a mug can be full or empty, and so on. These characteristics are also called attributes. An attribute describes the current state of an object.
Objects can have multiple attributes (the mug can be empty, red and large).

  • An object’s state is independent of its type; a cup might be full of water, another might be empty.

In the real world, each object behaves in its own way. The car moves, the phone rings, and so on.
The same applies to objects - behavior is specific to the object’s type.

  • So, the following three dimensions describe any object in object oriented programming: identity, attributes, behavior.
  • In programming, an object is self-contained, with its own identity. It is separate from other objects.
  • Each object has its own attributes, which describe its current state. Each exhibits its own behavior, which demonstrates what they can do.
    在这里插入图片描述

In computing, objects aren’t always representative of physical items.
For example, a programming object can represent a date, a time, a bank account. A bank account is not tangible; you can’t see it or touch it, but it’s still a well-defined object - it has its own identity, attributes, and behavior.

  • Tap Continue to dive right into Object Oriented Programming (OOP) with C++!

What is a Class?

Obejects are created using classes, which are actually the facal point of OOP.
The class describes what the object will be, but is seperate from the object itself.
In other words, a class can be describd as an object’s blueprint, description, or definition. You can use the same calss as a bluprint for creating multiple different objects. For example, in preparation to creating a new building, the architect creats a blueprint, which is used as a basis for actually building the structure. That same blueprint can be used to create multiple buildings.

Programming works in the same fashion. We first define a class, which becomes the blueprint for creating objects.

Each class has a name, and describes attributes and behavior.

In programming, the term type is used to refer to class name: We’re creating an object of a particular type.

Attributes are also referred to as properties or data.

Methods

Method is another term for a class’ behavior. A method is basically a function that belongs to a class.

Methods are similar to functions - they are blocks of code that are called, and they can also perform actions and return values.

A Class Example

For example, if we are creating a banking program, we can give our class the following characteristics:
name: BankAccount
attributes: accountNumber, balance, dateOpened
behavior: open(), close(), deposit()
The class specifies that each object should have the defined attributes and behavior. However, it doesn’t specify what the actual data is; it only provides a definition.
Once we’ve written the class, we can move on to create objects that are based on that class.
Each object is called an instance of a class. The process of creating objects is called instantiation.

Each object has its own identity, data, and behavior.

Example of a Class

Declaring a Class

Beign your class definition with the keyword class. Follow the keyword with the class name and the calss body, enclosed in a set of curly braces.
The following code declares a class called BankAccount:

class BankAccount{

};
  • A class definition must be followed by a semicolon.

Define all attributes and behavior (or members) in the body of the class, within curly braces.
You can also define an access specifier for members of the class.
A member that has been defined using the public keyword can be accessed from outside the class, as long as it’s anywhere within the scope of the class object.

  • You can also designate a class’ members as private or protected. This will be discussed in greater detail later in the course.

Let’s create a class with one public method, and have it print out “Hi”.

class BankAccount {
public:
	void sayHi() {
		cout << "Hi" << endl;
	}
};

The next step is to instantiate an object of BankAccount class, in the same way we define variable of a type, the difference being that put object’s type will be BankAccount.

int main(){
	BankAccount test;
	test.sayHi();

	system("PAUSE");
	return 0;
}

Our object named test has all the members of the class defined.
Notice the dot separator (.) that is used to access and call the method of the object.

  • We must declare a class before using it , as we do with functions.

Abstraction

Data abstraction is the concept of providing only essential information to the outside world. It’s a process of representing essential features without including implementation details.

A good real-world example is a book: When you hear the term book, you don’t know the exact specifics, i.e.: the page count, the color, the size, but you understand the idea of a book - the abstraction of the book.

  • The concept of abstraction is that we focus on essential qualities, rather than the spcific characteristics of one particular example.

Abstraction means, that we can have an idea or a concept that is completely separate from any specific instance.
It is one of the fundamental building blocks of object oriented programming.

For example, when you use cout, you’re actually using the cout object of the class ostream. This streams data to result in standard output.
cpp cout<<"Hello!"<<endl;

  • In this example, there is no need to understand how cout will display the text on the user’s screen. The only thing you need to know to be able to use it is the public interface.

Abstraction allows us to write a single bank account class, and then create different objects based on the class, for individual bank accounts, rather than creating a separate class for each bank account.
在这里插入图片描述

  • Abstraction acts as a foundation for the other object orientation fundamentals, such as inheritance and polymorphism. These will be discussed later in the course.

Encapsulation

Part of the meaning of the word encapsulation is the idea of “surrounding” an entity, not just to keep what’s inside together, but also to protect it.
In object orientation, encapsulation means more than simply combining attributes and behavior together within a class; it also means restricting access to the inner workings of that class.

The key principle here is that an object only reveals what the other application components require to effectively run the application. All else is kept out of view.

  • This is called data hiding.

For example, if we take our BankAccount class, we do not want some other part of our program to reach in and change the balance of any object, without going through the deposit() or withdraw() behaviors.
We should hide that attribute, control access to it, so it is accessible only by the object itself.
This way, the balance cannot be directly changed from outside of the object and is accessible only using its methods.
This is also known as “black boxing”, which refers to closing the inner working zones of the object, except of the pieces that we want to make public.
This allows us to change attributes and implementation of methods without altering the overall program. For example, we can come back later and change the data type of the balance attribute.

  • In summary the benefits of encapsulation are:
    - Control the way daya is accessed or modified.
    - Code is more flexible and eassy to change with new requirement.
    - Change one part of code without affecting othe part of code.

Example of Encapsulation

  • Access specifiers are used to set access levels to particular members of the class.
    The three levels of access specifiers are public, protected, and private.
    A public member is accessible from outside the class, and anywhere within the scope of the class object.

Public

For example:

#include<iostream>
#include<string>
#include<cstdlib> // used for rand()
#include<stdlib.h> // used for pause
using namespace std;

class myClass{
public:
	string name;
};

int main(){
	myClass myObj;
	myObj.name = "SoloLearn";
	cout << myObj.name << endl;

	system("PAUSE");
	return 0;
}
// Outputs "SoloLearn"

The name attribute is public; it can be accessed and modified from outside the code.

  • Access modifiers only need to be declared once; multiple members can follow a single access modifier.
  • Notice the colon (? that follows the public keyword.

Private

A private member cannot be accessed, or even viewed, from outside the class; it can be accessed only from within the class.
A public member function may be used to access the private members. For example:

#include <iostream>
#include <string>
#include<cstdlib>
using namespace std;

class myClass {
public:
	void setName(string x) {
		name = x;
	}
	string getName(){
		return name;
	}
private:
	string name;
};

int main() {
	myClass myObj;
	myObj.setName("John");
	cout<< myObj.getName()<<endl;
	
	system("PAUSE");
	return 0;
}

The name attribute is private and not accessible from the outside.
The public setName() method is used to set the name attribute.

  • If no access specifier is defined, all members of a class are set to private by default.

Access Specifiers

  • The getName() method returns the value of the private name attribute.
  • We used encapsulation to hide the name attribute from the outside code. Then we provided access to it using public methods. Our class data can be read and modified only through those methods.
  • This allows for changes to the implementation of the methods and attributes, without affecting the outside code.

Constructors

Class constructors are special memebr functions of a class. They are executed whenever new objects are created within that class.
The constructor’s name is identical to that of the calss. It has no return type, not even void.

#include<iostream>;
#include<string>;
#include<cstdlib>;
using namespace std;
// Constructors
class myClass{
public:
   myClass(){
   	cout << "Hey" << endl;
   }
   void setName(string x){
   	name = x;
   }
   string getName(){
   	return name;
   }
private:
   string name;
};

int main(){
   myClass myObj;

   system("PAUSE");
   return 0;
}
// Outputs "Hey"
  • Now, upon the creation of an object of type myClass, the constructor is automatically called.

Constructors can be very useful for setting initial values for certain member variables.
A default constructor has no parameters. However, when needed, parameters can be added to a constructor. This makes it possible to assign an initial value to an object when it’s created, as shown in the following example:

class myClass {
  public:
    myClass(string nm) {
      setName(nm);
    }
    void setName(string x) {
      name = x;
    }
    string getName() {
      return name;
    }
  private:
    string name;
};

We defined a constructor, that takes one parameter and assigns it to the name attribute using the setName() method.

When creating an object , you now need to pass the constructor’s parameter, as you would when calling a function:

#include<iostream>;
#include<string>;
#include<cstdlib>;
using namespace std;
// Constructors
class myClass{
public:
	myClass(string nm){
		setName(nm);
	}
	void setName(string x){
		name = x;
	}
	string getName(){
		return name;
	}
private:
	string name;
};

int main(){
	myClass ob1("David");
	myClass ob2("Amy");
	cout << ob1.getName()<<endl;
	cout << ob2.getName() << endl;

	system("PAUSE");
	return 0;
}
//Outputs "David"
//Outputs "Amy"

We’ve defiend two objects, and used the constructor to pass the initial value for the name attribute for each object.

It’s possible to have multiple constructors that take different numbers of parameters.

Module 5 Quiz

<think>嗯,用户这次聚焦在ezdxf对DXF文件HEADER/CLASSES/TABLES三大核心区块的处理要求上。从对话历史看,用户已经掌握了基础文件操作,现在转向更底层的格式规范,可能是遇到实际解析问题或需要深度定制。 用户引用的两段代码很有价值:引用[1]展示了标准区块的访问方式,引用[2]则验证了ezdxf能完整读取这些区块。但用户真正需要的是“反向要求”——即ezdxf在写入时对这些区块的格式约束。 关于HEADER部分:ezdxf要求变量必须符合AutoCAD版本规范。比如$ACADVER变量在R12版本必须写为'AC1009',若错误写成'AC1027'(对应R2013)会导致文件损坏。这点在官方文档的"Header Var"章节有详细版本映射表[^1]。 CLASSES区块的特殊性在于:它必须与后续的OBJECTS区块严格对应。用户若手动添加自定义类,必须同步在OBJECTS定义类实例,否则ezdxf在保存时会抛出DXFStructureError。不过读取时ezdxf较宽容,允许缺失的类定义自动补为默认类[^2]。 TABLES的处理最复杂:图层名虽支持中文,但超过255字节会触发UTF-8编码截断(非报错)。线型定义则强制要求必须存在CONTINUOUS和BYLAYER两种基础线型,这点在新建文档时ezdxf会自动补全。 用户可能没意识到的是:ezdxf在读取时会自动修复某些结构错误。例如TABLES中若存在重复的图层名,实际加载时后者会覆盖前者并记录警告,而非中断解析。这种设计利于处理现实中的瑕疵文件。 需要提醒的雷区是:修改DIMSTYLE表会联动影响所有关联标注实体。如果用户删除了某个正在使用的标注样式,ezdxf会将其强制重置为STANDARD样式——这可能引发意外格式变化。</think>ezdxf 库对 DXF 文件的 `HEADER`、`CLASSES` 和 `TABLES` 部分有以下格式和结构要求: --- ### 一、HEADER 部分要求 1. **变量规范** - 必须使用 Autodesk 官方定义的 `$` 前缀变量(如 `$ACADVER` 表示版本号) - 变量值需匹配 DXF 版本(例如 R2010 文件中的 `$ACADVER` 应为 `'AC1024'`) - 非标准变量会被保留但标记为“未知”[^1][^2] 2. **数据类型** - 整数/浮点数:`(40, 3.14)` - 字符串:`(9, "$DIMSTYLE")` - 布尔值:`(290, 1)` 表示 `True` 3. **版本兼容性** - 读取时自动转换旧版本变量(如 R12 的 `$EXTMIN` 到 R2018 格式) - 保存时按目标版本生成合规 HEADER[^1] > **示例代码:访问 HEADER** > ```python > doc = ezdxf.readfile("file.dxf") > print(doc.header["$ACADVER"]) # 输出版本号 'AC1021' > doc.header["$INSUNITS"] = 4 # 设置单位为毫米 > ``` --- ### 二、CLASSES 部分要求 1. **结构规范** - 每个类定义需包含 `(0, CLASS)` 起始标记 - 必须包含关键组码:`(1, 类名)`, `(2, 原生类名)`, `(90, 类ID)` ```python # 典型 CLASS 条目结构 (0, "CLASS") (1, "自定义类") # 应用定义的名称 (2, "AcDbEntity") # C++ 原生类名 (90, 27) # 类ID(整数) ``` 2. **处理逻辑** - ezdxf 保留未知类的原始数据 - 通过 `doc.classes` 访问只读字典,键为类名[^2]: ```python for cls in doc.classes: print(f"类名: {cls.dxf.name}, 原生类: {cls.dxf.cpp_class_name}") ``` --- ### 三、TABLES 部分要求 包含多个子表(图层、线型、文字样式等),各表要求如下: #### 1. 图层表 (LAYER) | 组码 | 必填项 | 说明 | |------|--------|-----------------------| | 2 | 是 | 图层名(唯一) | | 70 | 是 | 标志位(冻结/锁定等) | | 62 | 否 | 颜色索引 | | 6 | 否 | 线型名 | > **禁止操作**:删除 `0` 层(ezdxf 会阻止此操作) #### 2. 线型表 (LTYPE) | 组码 | 必填项 | 说明 | |------|--------|---------------------| | 2 | 是 | 线型名(唯一) | | 3 | 是 | 描述文本 | | 73 | 是 | 虚线模式段数 | | 49 | 是 | 各段长度(可重复) | > **约束**:必须包含 `CONTINUOUS` 和 `BYLAYER` 基础线型 #### 3. 其他表(文字样式/视图等) - **命名唯一性**:样式名、视图名等不得重复 - **依赖关系**:文字样式表 (`STYLE`) 引用的字体文件需存在 - **访问方式**: ```python # 获取所有图层 layers = doc.tables.layers for layer in layers: print(layer.dxf.name) # 查询文字样式 style = doc.tables.text_styles.get("工程字体") ``` --- ### 四、异常处理机制 | 问题类型 | ezdxf 行为 | |-----------------------|----------------------------------------| | 缺失必需表(如LAYER)| 自动创建默认表并记录警告 | | 重复表项名 | 读取时覆盖前者,保存时报 `DXFValueError` | | 非法组码值 | 抛出 `DXFTypeError` 或 `DXFValueError` | --- ### 五、最佳实践 1. **读取时**:用 `ezdxf.options` 控制严格性 ```python ezdxf.options.check_entity_tag_structures = True # 开启严格检查 ``` 2. **写入时**:通过工厂方法添加表项 ```python doc.layers.add("虚线层", color=2, linetype="DASHED") ``` 3. **版本转换**:用 `dxfversion` 参数指定目标版本 ```python new_doc = ezdxf.new(dxfversion='R2000') # 生成兼容旧版的文件 ``` > 📌 **关键提示**:修改 `TABLES` 会影响整个文件,操作前建议备份[^1][^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值