C++ study notes (7)-class
The basic idea of classes is data abstraction and encapsulation. Encapsulation implements the separation of the interface and implementation of the class. Data abstraction is a programming technique that relies on separation of interface and implementation.
define abstract data types
Define the improved Sales_data
class
struct Sales_data{
std::string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price() const;
// 数据成员
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
}
// Sales_data 的非成员接口函数
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream &print(std::ostream&, const Sales_data&);
std::istream &read(std::istream&, Sales_data&);
A function defined inside a class is an implicit
inline
functionAll members must be declared inside the class, but the member function body definition can be inside or outside the class
this
It is an implicit parameter of a member function, initialized by the address of the function object, a constant pointer, pointing to the object itself, and cannot be changed.Constant member function (
const member function
): A keyword is added after the parameter list of the member functionconst
to modify the type of the implicitthis
pointer, making it a constant pointer to a constant objectconst Sales_data *const
. Cannot bind to a const object because the defaultthis
type is a const pointer to a non-const version of the class typeSales_data *const
.this
Constant member functions cannot modify object contents.std::string isbn() const { return bookNo; }
Constant objects and references or pointers to constant objects can only call constant member functions
The compiler processes classes in two steps, first compiling class member declarations, then to member function bodies. Therefore, the member function body can freely use other members of the class.
Define class-related non-member functions
The class needs some auxiliary functions such as the above add
, read
etc. These functions belong to the interface component of the class, and do not actually belong to the class itself
If non-member functions are part of a class interface, the declarations of these functions should be in the same header file as the class
IO classes are types that cannot be copied, so they can only be passed by reference
istream &read(istream &is, Sales_data &item) { double price = 0; is >> item.bookNo >> item.units_sold >> price; item.revenue = price * item.units_sold; return is; }
Constructor
The constructor is used to control the initialization process of its object.
The constructor has the same name as the class and has no return type
The constructor cannot be declared as
const
, when the object of the class is created , until theconst
constructor completes the initialization process, the object really gets the常量
propertiesDefault Constructor : The class controls the default initialization process through a special constructor that does not require any arguments. When a class does not explicitly define a constructor, the compiler implicitly defines a default constructor, also known as
合成的默认构造函数
If a class contains members of a built-in type or a composite type, it should be given an in-class initial value so that the class is eligible to use a synthetic default constructor, otherwise default-initialized and its value is undefined.
The new C++11 standard defines that use after the parameter list
= default
requires the compiler to generate a constructor.struct Sales_data{ Sales_data() = default; }
Constructor initializer list: responsible for assigning initial values to one or more data members of the newly created object
Sales_data(const std::string &s, unsigned n, double p): bookNo(s), units_sold(n), revenus(p*n) {}
Access Control and Encapsulation
C++ uses access specifiers to enhance encapsulation
- Members defined after
public
the specifier are accessible throughout the program - A member defined
private
after a specifier can be accessed by class member functions, but not by code that uses the class
- Members defined after
struct
andclass
the default access permissions are not the same.class
The default for the keyword isprivate
Friend : A class can make other classes or functions friends of the class, so that other classes or functions can access its non-public members
friend Sales_data add(const Sales_data&, const Sales_data&);
The friend declaration only specifies the authority of the model text, not the function declaration in the usual sense. It is better to declare the function again outside the friend declaration.
Other properties of the class
Class membership revisited
inline
It can be used in the function declaration inside the class, and it can also be used in the function definition outside the classMutable data member (mutable) : never
const
, even if it isconst
a member of an object, i.e. aconst
member function can change the value of a mutable memberclass A { public: void add() const { ++b; // 成立,因为是可变成员 mutable } private: mutable int b; // 即使在一个`const`对象内也能被修改 }
*this
member function that returns
- If a
const
member function returns by reference*this
, its return type will be a constant reference const
A member function can be overloaded by distinguishing whether it is or not , for reasons similar to whether a pointer in a function parameter isconst
class type
- Forward declaration : The function declaration is separated from the definition. After the declaration, it is an incomplete type before the definition, that is, only the class type is known, but it is not clear which members are included
- The use of incomplete types is very limited: you can define pointers or references to incomplete types, and you can also declare (but not define) functions that take incomplete types as parameters or return types.
Friends of Yuan revisited
Friendship between classes
class Screen{
friend class Window_mgr; // Window_mgr 的成员可以访问 Screen 类的私有部分
};
- If the class specifies a friend class, the member functions of the friend class can access all members of this class, including non-public members
- There is no transitivity in the friend relationship, that is,
window_mgr
the friend class does not have accessScreen
privileges - Each class is responsible for controlling its own friend class or friend function
Make member functions a friend
class Screen{
friend void Window_mgr::clear(ScreenIndex); // Window_mgr::clear必须在Screen类之前被声明
}
Friend Function Design Rules
- First define
Window_mgr
the class, in whichclear
functions are declared, but not defined. Must be declared before usedclear
membersScreen
Screen
- Next define
Screen
, includingclear
friend declarations for - Finally define a member
clear
at which point it can be usedScreen
Friend declarations and scope
The role of the friend declaration is to affect access rights, not a declaration in the ordinary sense
struct X{ friend void f() { /* 友元函数可以定义在类内部 */} X() { f(); } // 错误:f 还没有被声明 void g(); void h(); }; void X::g() { return f(); } // 错误:f 还没有被声明 void f(); // 声明那个定义在 X 类中的函数 void X::h() { return f(); } // 正确:现在 f 的声明在作用域中了
class scope
A class is a scope, so defining a class member function externally needs to provide the class name and function name. Outside the class, the name of the member will be hidden
Member function definitions are not processed until the compiler has processed all declarations in the class
If the outer object is hidden, it can be accessed using the scope operator
void Screen::dummy_fcn(pos height){ cursor = width * ::height; // 全局变量height }
Constructor revisited
Constructor initializer list
- If the initializer member does not appear in the initializer list of the constructor, the member is default-initialized before the constructor body
- The initial value of the constructor is initialization, and the assignment is performed in the body of the constructor
- If the member is a
const
, reference, or some class type that does not provide a default constructor, it must be initialized via the constructor initializer list. - The difference between initialization and assignment is a matter of underlying efficiency
- Initialization is the direct initialization of data members
- Assignment is first initialization and then assignment
- Member initialization order is consistent with the order in which they appear in the class definition, and try to avoid using some members to initialize other members
- If a constructor provides default arguments for all parameters, it actually defines a default constructor as well
Delegate constructor
C++11 defines a delegating constructor : you can use other constructors of the class to which it belongs to perform its initialization process
class Sales_data{
public:
// 非委托构造函数使用对应的实参初始化成员
Sales_data(std::string s, unsigned cnt, double price): bookNo(s), units_sold(cnt), revenue(cnt * price) {}
// 委托构造函数将初始化过程委托给另一个构造函数,先执行被委托的上述构造函数,在执行本函数体
Sales_data(): Sales_data("", 0, 0) {}
}
- Execute the delegated constructor first, and then execute the delegator's function body
Implicit class type conversion
Conversion constructor : If the constructor accepts only one argument, it actually defines an implicit conversion mechanism to convert to this type of type, such a constructor is called a conversion constructor
string null_book = '9-999=99999-9'; // 构造临时Sales_data对象,对象的units_sold 和 revenue 为0, bookNo 等于 null_book item.combine(null_book);
The compiler will only perform one type conversion automatically
// 错误:需要两步转换,先将字符串字面值转为string,再将临时的string对象转换成Sales_data对象 item.combine("9-999-99999-9"); item.combine(string("9-999-99999-9")); // 正确:显示转换成 string,隐式转换成 Sales_data
explicit
Implicit conversions can be prevented by declaringexplicit
a constructor to be valid only for constructors with one argument, and constructors that require multiple arguments cannot be used to perform implicit conversions.class Salse_data{ public: explicit Sales_data(const std::string &s): bookNo(s) {} }
The keyword can only be used when declaring a constructor inside a
explicit
class, and should not be repeated when defining outside a classexplicit
Constructors can only be used for direct initialization, not for copy initialization
Aggregate class
Aggregate class means that users can directly access its members, and has a special initialization syntax form, the conditions are as follows
- all members
public
are - no constructors defined
- no in-class initializer
- No base classes and no
virtual
functions
literal constant class
Requirements for Literal Constant Classes
- Data members must be literal types
- Class must have at least one
constexpr
constructor - If a data member has an in-class initial value, the initial value of the built-in type member must be a constant expression; or if the member is of a class type, the initial value must use the member's own
constexpr
constructor - A class must use the default definition of a destructor, the member responsible for destroying objects of the class
constexpr
Constructor
Constructors cannot be const
, but constructors of literal constant classes can make constexpr
functions
constexpr Debug(bool h, bool i, bool o): hw(h), io(i), other(o) {}
constexpr
The constructor must initialize all data members, the initial value uses theconstexpr
constructor or a constant expression
static member of class
A member associated with a class rather than an object is a static member, and a keyword can be added before the member declaration static
. A static member can be public
OR private
, and the type can be a constant, a reference, a pointer, or a class type, etc.
A static member function cannot be declared as
const
static
Pointers cannot be used in the function bodythis
, because static member functions are not bound to objects, and there are nothis
pointersStatic members can be accessed directly using scope operators, static members can be accessed using class objects, references or pointers
double r; r = Account::rate(); // 使用作用域运算符访问静态成员 Account ac1, *arc = &ac1; // 调用静态成员函数 rate 的等价形式 r = ac1.rate(); // 通过 Account 的对象或引用 r = ac2->rate(); // 通过指向 Account 对象的指针
Member functions can use static members directly without going through the scope operator
static
Keywords can only appear in declaration statements inside a classBecause static data members do not belong to any of the tired objects, static members cannot be initialized inside the class, each static member must be defined and initialized outside the class, and static data members can only be defined once
If the static member is of literal constant type
constexpr
, an in-class initial value of integer type can be provided for the static memberconst
, and the initial value must be a constant expressionA static data member can have an incomplete type, in particular, the type of the class to which it belongs. Non-static members are restricted and can only be declared as pointers or references to the class to which they belong
Static members can be used as default arguments, but ordinary members cannot
Epilogue
Class is the most basic feature in the C++ language, and has two basic capabilities: data abstraction, which is the ability to define data members and function members; the second is encapsulation, which is the ability to protect class members from being freely accessed. private
Encapsulation is achieved by setting the implementation details of the class to . Classes can make other classes or functions friends so they can access non-public members of the class
Classes can define constructors, which are used to initialize objects. Constructors can be overloaded, all data members should be initialized using the constructor initializer list
A class can also define mutable or static members, a mutable member can never be const
, and its value can be modified even within a const
member function; a static member can make a function or data, and a static member exists outside of all objects .