[C++] Class (part 1)
The fundamental ideas behind classes are data abstraction and encapsulation.
Data abstraction is a programming technical that relies on the separation of interface(declaration) and implementation(definition)
A class designer desings and implements a class for users of that class.
In this class, the user is a progrmmer, not the utilmate user of the application.
Every member must be declared inside its class, and we can difine a member's body either inside or outside of the class body.
Objects that are const, and references or pointers to const objects may call only const member functions.
The compiler process class in two steps
- the member declarations are compiled first
- the member function bodies are processed.
The name of a member defined outside the class must inlucde the class name.
class Sales_data::arg_print() const{
if (units_sold){
return revenue / units_sold;
} else {
return ;
}
}
Define a funcion to return "this" object
Sales_data & Sales_data::combine(const Sales_data & rhs){
units_sold += rhs.units_sold;
return *this; // return current object
}
To return an lvalue, our combine function must return a reference.
Member functions that are part of the interface of a class should be declared in the same header as the class itself.
istream & read(istream & is, Sales_data & item){
is >> itme.bookNo >> item.units_sold;
return is;
}
ostream & print(ostream & os, const Sales_data & item){
os << item.isBN();
return os;
}
Both read an writer take a reference to thier respective IO class types. The IO class cannot be copied, so only passed by reference.
Reading or Writing to a stream changes that stream, so both functions take ordinary reference, not references to const.
Sales_data add(const Sales_data & lhs, const Sales_data & rhs){
Sales_data sum = lhs; // copy data members from lhs into sum. statement[1]
sum.combine(rhs);
return sum;
}
We initialize sum as a copy of lhs. By default, copying a class object copies that object's members.
In Java, statement[1] only assign the reference of lhs to sum. Both sum and lhs points to the same object in heap storage.
In C++, statement[1] copy the all member from lhs to sum. lhs and sum points to different object, and are independent.
The compiler generate a default constructor automatically only if a class declare no constructors.
Many class that need dynamic memory can (and generally should) use a vector or a string to manage the necessary storage. Classes that use vectors and string avoid the complexites of allocating and deallocating memory.
A class may contain zero or more access specifier(e.g. private, public). Each access specifier specify the access level of the succeeding members. The specified access level remain in effect until the next access specifier or the end of the class body.
The only difference between struct and class is the default access level.
- In struct, the members defined before the first accesss specifier are public.
- In class, these members are private.
Friend
A class can allow class or function to access its non-public members by marking that as a frined.
class Sales_data{
friend Sales_data add(const sales_data&, const Sales_data&);
public:
Sales_data() default;
private:
string bookNo;
};
// declarations for members which are part of the Sales_data interface
Sales_data add(const Sales_data&, const Sales.data &);
It is good idea to group friend declaration together at the beginning or end of the class. To make a friend visible to the users of the class, we usually declare each friend(outside the class) in the same header as the class.
Encapsulation provide two important advantage:
- User code cannot corrupt the state of an encapsulated object
- The implementation of an encapsulated class can change over time without requiring changes in user-level code.
Although user code need not change when a class definition changes, the source files that use a class must be re-compiled if the class changes.
Class often have small functions that can benefit from being inline.
Mutable
A mutable data member are never const, even when it is a member of a const class
class Screen{
public:
void some_member() const;
private:
mutable size_t access_ctr; // may change even in a const object
};
void Screen::some_member() const{
access_ctr++;
};
In-class initializer
When we provide an in-class initializer, we must do so following on = asign or inside braces.
class windows_mgr{
private:
// By default, a windows_mgr has one blank screen
std::vector<Screen> screens{screen(, , ' ')};
}
Return *this
class Screen{
public:
Screen& set(char);
Screen& move(int i, int j);
// other members. e.g. cursor
};
inline Screen& Screen::move(int i, int j){
cursor = i * width + j;
return *this; // return this object as lvalue
}
inline Screen& Screen::set(char c){
contents[cursor] = c;
return *this;
}
If we concatenate a sequence of these actions into a single expression
myScreen.move(, ).set('#');
Above single expression is equal to
myScreen.move(, );
myScreen.set('#');
Had we defined move and set to return Screen, rather thane Screen &. This statement will be vary different.
Screen tmp = myScreen.move(, ); // the return value would be copied
tmp.set('#'); // the content inside myScreen will be unchanged.
A class is not defined until its class body is completed. A class cannot have data members of its own type.
However, a class is considered declared(not yet defined) as soon as its calss name has been seen. Therefore, a class can have data members that are pointers or reference to its own type.
class Link_Sales{
Screen window;
Link_Sales *next;
Link_Sales *prev;
};
class Screen{
// Windows_mgr can access the non-public part of class Screen.
friend class Windows_mgr;
}
void Windows_mgr::clear(int i){
Screen & s = screens[i];
s.content = '';
}
It is important to understand that friendship is not transitive. If class Windows_mgr has its own friends, that friends have no special access to Screen.
Each class controls which class or function are its friends.
Although overload functions share a common name, they are still different functions. Therefore a class must define as a friend each function in a set of overload functions that it wish to mark as friend.
The lookup rules for friends
Struct X{
friend void f();
X() { f(); } // error: no declaration for f()
void g();
void h();
}
void X::g() { return f(); } // error: f has not been declared
void f(); // declares the function defined in X()
void X:h() { return f(); } // ok
Remember, some compiler do not enforce the lookup rules for friends.
class Window_mgr{
public:
screenIndex addScreen( const Screen&);
// other members
};
// return type is seen before the scope of Window_mgr
Window_mgr::ScreenIndex Window_mgr::addScreen(const Screen & s){
screens.push_back(s);
return screens.size() - ;
}
To use screenIndex for the return type, we must specified.
Member function definitions are processed after all of the declaration in class are processed by compiler. So member functions can use any member declared inside the calss
Even though the class member(height) is hidden, it is accessable by qualified the member's name with the class's name or with this pointer expectly
void Screen::dummy_fcn(pos height){
cursor = width * this->height;
// alternative way
cursor = width * Screen::height;
}
The global object is accessable by the scope opertion.
void Screen::dummy_fcn(pos height){
cursor = width * ::height; // the global height
}
Reference:
C++ Primer, Fifth Edition, chapter 7 Classes
随机推荐
- iOS多语言设置
最近公司做的项目需要向国外推广,因此app需要添加相应的语言设置,为此整理记录下多语言设置的过程.如有不对的地方,欢迎各位大神指正.下面就详细介绍下设置的过程: 1.基本设置 第一步:首先在 项目工程 ...
- 【Java】使用Atomic变量实现锁
Atomic原子操作 在 Java 5.0 提供了 java.util.concurrent(简称JUC)包,在此包中增加了在并发编程中很常用的工具类 Java从JDK1.5开始提供了java.uti ...
- Linux学习笔记——1.超级用户
以超级用户工作:su su命令允许临时变换到任何一用户标识(如果拥有口令的话),并挂起当前shell,为新用户开启一个新的shell. su <user> 将当前用户标识harley变换为 ...
- 为什么后台返回的日期我输出处理了在苹果手机里显示NAN?
现象: //结束时间var ent_time ="2018-04-28 09:36:00"alert((Date.parse(new Date(ent_time))));/ ...
- python基础 抽象类(接口类)
Python中没有接口.接口类,抽象类:定义 制定一个规范 #必须要导入from abc import ABCMeta,abstractmethod class Payment(metaclass = ...
- ruby 批量下载王者荣耀皮肤
主要采用ruby Parallel库提供的多线程方式: require 'unirest' require 'open-uri' require 'parallel' require 'json' u ...
- openwrt从0开始-目录
终于下定决心把近期的笔记整理一下.涉及到方方面面,记录自己的成长和沉淀自己所学. 预备知识:linux, 网络通信,待补充... 目录: 前言:openwrt简介 1. openwrt源码下载及编译环 ...
- java语言描述 猴子吃桃问题(递归和循环写法)
//题目:猴子吃桃问题:猴子第一天摘下若干个桃子,当即吃了一半,还不瘾,又多吃了一个//第二天早上又将剩下的桃子吃掉一半,又多吃了一个//以后每天早上都吃了前一天剩下 的一半零一个.到第10天早上想再 ...
- Asp.net core静态文件目录访问
Asp.net core静态文件目录访问 如果使用Asp.net core来实现一个能够访问其它电脑上的资源 新建工程 选择项目框架 如何将静态文件注入到项目中 在startup.cs文件的Confi ...
- [NOIP2017]列队(树状数组)
定义第i行为所有的点(i,j),0<j<m 可以发现,每一行是相对独立的,每一次操作只会影响到当前行和最后一列 考虑每一行和最后一列各开一个树状数组,但这样显然会爆空间 实际上,对于没有离 ...