【C++ grammar】对象和类

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 circle
  double radius;
  
  // Construct a circle object
  Circle() {
    
    
    radius = 1;
  }
  
  // Construct a circle object
  Circle(double newRadius) {
    
    
    radius = newRadius;
  }
  
  // Return the area of this circle
  double 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 circle
  double radius;
  // Construct a circle object
  Circle() {
    
    
    radius = 1;
  }
  // Construct a circle object
  Circle(double newRadius) {
    
    
    radius = newRadius;
  }
  // Return the area of this circle
  double 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 radius
  circle2.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 è variables

double d1;  //未初始化

double d2(3.3);  

int  x1{
    
    2.0}; //error: Narrowing

int  x2={
    
    4};

auto i{
    
    x};

decltype(d1) j;

1.2. 定义对象的例子:

// class è objects

Circle c1;      //调用Circle的默认ctor

Circle c2(5.5); //调用Circle的有参ctor

Circle c3{
    
    5.5}; // 直接列表初始化,调有参ctor

Circle c4 = {
    
    5.5}; // 拷贝列表初始化,调ctor

auto 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{
    
    };           // 直接列表初始化,调默认Ctor
  c3 = 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、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++11
  double 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是一个运算符

猜你喜欢

转载自blog.csdn.net/qq_42604176/article/details/109144736