C++ Classes (I)

C++ Classes (I)

Classes are an expanded concept of data structures: like data structures, they can contain data members, but they can also contain functions as members.

类是一个结构体的扩展,里面不仅有结构体包含的函数,也有结构体中没有包含的函数,这里指的是方法。

An object is an instantiation of a class. In terms of variables, a class would be the type, and an object would be the variable.

一个对象是一个类的实例,就变量而言,一个类将定义一个类型,而对象将会定义一个变量。

Classes are defined using either keyword class or keyword struct, with the following syntax:

class class_name {
  access_specifier_1:
    member1;
  access_specifier_2:
    member2;
  ...
} object_names;

Where class_name is a valid identifier for the class, object_names is an optional list of names for objects of this class. The body of the declaration can contain members, which can either be data or function declarations, and optionally access specifiers.

内容可以是数据或者函数,又或者是任意的 访问说明符(如public,private····)这之类的。

访问说明符的解释:
Classes have the same format as plain data structures, except that they can also include functions and have these new things called access specifiers. An access specifier is one of the following three keywords: private, public or protected. These specifiers modify the access rights for the members that follow them:

1.private members of a class are accessible only from within other members of the same class (or from their “friends”).
2.protected members are accessible from other members of the same class (or from their “friends”), but also from members of their derived classes.
3.Finally, public members are accessible from anywhere where the object is visible.

private 只能被这个相同类的内部成员来进行访问
protected 除了能被这个类内部的成员进行访问,也可以被这个类所派生的其他成员所访问。
public 可以被任何地方的对象所见。

By default, all members of a class declared with the class keyword have private access for all its members. Therefore, any member that is declared before any other access specifier has private access automatically. For example:

class Rectangle {
    int width, height;
  public:
    void set_values (int,int);
    int area (void);
} rect;

注意,如果没有指明关键字,则C++默认使用private,如上面,width和height是private,而set_values()和area()则是public,默认的这个设定是你需要明确的。

举个例子:

#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    void set_values (int,int);
    int area() {return width*height;}
};

void Rectangle::set_values (int x, int y) {
  width = x;
  height = y;
}

int main () {
  int a,b;
  Rectangle rect;

  rect.width=3;
  cin >> a >> b;
  rect.set_values (a,b);
  cout << "area: " << rect.area() << endl;
  return 0;
}

这里知道为什么要将变量设为私有的了吧,这样只能通过其类的方法来改变变量,如果你直接rect.width=3这种指令,则会明显进行报错,这种道理是你需要明确的。

Constructors

What would happen in the previous example if we called the member function area before having called set_values? An undetermined result, since the members width and height had never been assigned a value.

In order to avoid that, a class can include a special function called its constructor, which is automatically called whenever a new object of this class is created, allowing the class to initialize member variables or allocate storage.

需要在声明类的对象时给这这个类进行初始化,这个操作操作由一个特殊的函数来完成,其叫做构造器(Constructors)。

This constructor function is declared just like a regular member function, but with a name that matches the class name and without any return type; not even void.

关于构造器的声明问题,这个和普通的函数没有什么两样,要说不同,那么主要是其声明是不加任何返回类型,甚至连void都不会加的,明确这个那么就很好理解了。

class Rectangle {
    int width, height;
  public:
    Rectangle (int,int);
    int area () {return (width*height);}
};

Rectangle::Rectangle (int a, int b) {
  width = a;
  height = b;
}

下面来声明函数时就可以这样来声明:

Rectangle rect (3,4);
Rectangle rectb (5,6);

Overloading constructors

Like any other function, a constructor can also be overloaded with different versions taking different parameters: with a different number of parameters and/or parameters of different types. The compiler will automatically call the one whose parameters match the arguments:

像其他的函数一样,这个构造器也可以根据其传入参数的类型来选择不同的函数,这被称为函数重载,实现这个也很简单,没有什么太大的问题。

// overloading class constructors
#include <iostream>
using namespace std;

class Rectangle {
    int width, height;
  public:
    Rectangle ();
    Rectangle (int,int);
    int area (void) {return (width*height);}
};

Rectangle::Rectangle () {
  width = 5;
  height = 5;
}

Rectangle::Rectangle (int a, int b) {
  width = a;
  height = b;
}

int main () {
  Rectangle rect (3,4);
  Rectangle rectb;
  cout << "rect area: " << rect.area() << endl;
  cout << "rectb area: " << rectb.area() << endl;
  return 0;
}

可以看到第一个定义时用到了构造器2,而第二个则用到了构造器1。

这里不必多言。

Uniform initialization

统一初始化

The way of calling constructors by enclosing their arguments in parentheses, as shown above, is known as functional form. But constructors can also be called with other syntaxes:

构造器可以像一般的函数格式一样像圆括号里传递相关参数,但除此之外,构造器也有它自己专门的语法。

First, constructors with a single parameter can be called using the variable initialization syntax (an equal sign followed by the argument):

class_name object_name = initialization_value;

首先,可以利用等式直接在声明函数时为其赋值,即初始化。

More recently, C++ introduced the possibility of constructors to be called using uniform initialization, which essentially is the same as the functional form, but using braces ({}) instead of parentheses (()):

class_name object_name { value, value, value, ... }

这里可以使用大括号,而不是用函数所使用的括号,看个例子就会明确了:

// classes and uniform initialization
#include <iostream>
using namespace std;

class Circle {
    double radius;
  public:
    Circle(double r) { radius = r; }
    double circum() {return 2*radius*3.14159265;}
};

int main () {
  Circle foo (10.0);   // functional form
  Circle bar = 20.0;   // assignment init.
  Circle baz {30.0};   // uniform init.
  Circle qux = {40.0}; // POD-like

  cout << "foo's circumference: " << foo.circum() << '\n';
  return 0;
}

An advantage of uniform initialization over functional form is that, unlike parentheses, braces cannot be confused with function declarations, and thus can be used to explicitly call default constructors:

这里说明了它的有关优势,使用大括号可以避免与函数来混淆,进而明确自己在使用构造器。

Member initialization in constructors

下面介绍构造器在进行数字输出化的几种方式,而这些都可以,应该靠你灵活使用。

class Rectangle {
    int width,height;
  public:
    Rectangle(int,int);
    int area() {return width*height;}
};

第一种:

Rectangle::Rectangle (int x, int y) { width=x; height=y; }

第二种:

Rectangle::Rectangle (int x, int y) : width(x) { height=y; }

第三种:

Rectangle::Rectangle (int x, int y) : width(x), height(y) { }

注意,变量中使用()这种是可以的,最后一种注意这是一个空函数,但必须要定义。

For members of fundamental types, it makes no difference which of the ways above the constructor is defined, because they are not initialized by default, but for member objects (those whose type is a class), if they are not initialized after the colon, they are default-constructed.

我们上面说明了那么多种定义方法,似乎不能看出其有什么作用,因为对于不同类的定义,它们真的没什么区别,但对于下面的一些类中类,我们就可以体现出其具体的作用了。

Default-constructing all members of a class may or may always not be convenient: in some cases, this is a waste (when the member is then reinitialized otherwise in the constructor), but in some other cases, default-construction is not even possible (when the class does not have a default constructor). In these cases, members shall be initialized in the member initialization list. For example:

采用默认的构造方式在有些条件下可能并不是那么方面的,有时是一种浪费(当这些数字又被在构造器中重新初始化一遍),但在另一些类中,默认的构造器身值是无法实现的(当这个类并没有一个默认的构造器),在这个例子中,成员将被初始化在一个成员初始化列表中,如:

// member initialization
#include <iostream>
using namespace std;

class Circle {
    double radius;
  public:
    Circle(double r) : radius(r) { }
    double area() {return radius*radius*3.14159265;}
};

class Cylinder {
    Circle base;
    double height;
  public:
    Cylinder(double r, double h) : base (r), height(h) {}
    double volume() {return base.area() * height;}
};

int main () {
  Cylinder foo (10,20);

  cout << "foo's volume: " << foo.volume() << '\n';
  return 0;
}

这里你可以看到“类中类”,你如何初始化最里面的类呢?在类中再调用一次最里面类的构造器?太麻烦不切实际,而你使用base (r)

注意,这里我们是“事后补加”,我们在类中申请这个类的实例,我们不会给它初始化,而是和外类的对象一起初始化,就是这个样子。

Pointers to classes

这里是关于类的指针,这个指针指向对象。

Rectangle * prect;

对类中的对象的操作很灵活,具体的操作如下:

// pointer to classes example
#include <iostream>
using namespace std;

class Rectangle {
  int width, height;
public:
  Rectangle(int x, int y) : width(x), height(y) {}
  int area(void) { return width * height; }
};


int main() {
  Rectangle obj (3, 4);
  Rectangle * foo, * bar, * baz;
  foo = &obj;
  bar = new Rectangle (5, 6);
  baz = new Rectangle[2] { {2,5}, {3,6} };
  cout << "obj's area: " << obj.area() << '\n';
  cout << "*foo's area: " << foo->area() << '\n';
  cout << "*bar's area: " << bar->area() << '\n';
  cout << "baz[0]'s area:" << baz[0].area() << '\n';
  cout << "baz[1]'s area:" << baz[1].area() << '\n';       
  delete bar;
  delete[] baz;
  return 0;
}   

可以看出,有数组,可以进行数组对象的初始化,随着学习的深入,我们对这个的了解将会越来越深刻,现在先了解就好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值