C++ Classes (II)

Classes (II)

Overloading operators

int a, b, c;
a = b + c;

这是int类型的可以进行这样操作,但是,我们如果让类的对象来进行这种操作呢?就像这样:

Here, different variables of a fundamental type (int) are applied the addition operator, and then the assignment operator. For a fundamental arithmetic type, the meaning of such operations is generally obvious and unambiguous, but it may not be so for certain class types. For example:

struct myclass {
  string product;
  float price;
} a, b, c;
a = b + c;

C++显然提供了这种可能性:

Here, it is not obvious what the result of the addition operation on b and c does. In fact, this code alone would cause a compilation error, since the type myclass has no defined behavior for additions. However, C++ allows most operators to be overloaded so that their behavior can be defined for just about any type, including classes. Here is a list of all the operators that can be overloaded:

                    Overloadable operators

+    -    *    /    =    <    >    +=   -=   *=   /=   <<   >>
<<=  >>=  ==   !=   <=   >=   ++   --   %    &    ^    !    |
~    &=   ^=   |=   &&   ||   %=   []   ()   ,    ->*  ->   new 
delete    new[]     delete[]

上面这些操作符都可以被定义为新的含义,举个例子就会明确了。

Operators are overloaded by means of operator functions, which are regular functions with special names: their name begins by the operator keyword followed by the operator sign that is overloaded. The syntax is:

type operator sign (parameters) { /*... body ...*/ }

这里可以举一个例子:

// overloading operators example
#include <iostream>
using namespace std;

class CVector {
  public:
    int x,y;
    CVector () {};
    CVector (int a,int b) : x(a), y(b) {}
    CVector operator + (const CVector&);
};

CVector CVector::operator+ (const CVector& param) {
  CVector temp;
  temp.x = x + param.x;
  temp.y = y + param.y;
  return temp;
}

int main () {
  CVector foo (3,1);
  CVector bar (1,2);
  CVector result;
  result = foo + bar;
  cout << result.x << ',' << result.y << '\n';
  return 0;
}

这是来实现笛卡尔坐标加法运算的。
操作符+,需要两个操作数,可以看出,一个给了x,另一个给这个声明的一个变量,而两个操作最终结果得以返回。

If confused about so many appearances of CVector, consider that some of them refer to the class name (i.e., the type) CVector and some others are functions with that name (i.e., constructors, which must have the same name as the class). For example:

CVector (int, int) : x(a), y(b) {}  // function name CVector (constructor)
CVector operator+ (const CVector&); // function that returns a CVector  

The function operator+ of class CVector overloads the addition operator (+) for that type. Once declared, this function can be called either implicitly using the operator, or explicitly using its functional name:

c = a + b;
c = a.operator+ (b);

通过这个就比较好理解了,一旦声明好+操作符重载,那么就等于声明了一个a的方法,然后在方法中将b作为参量来传递进来。

只不过C++隐藏了一些细节,实质是一样的,这样我们就很好理解了。

The operator overloads are just regular functions which can have any behavior; there is actually no requirement that the operation performed by that overload bears a relation to the mathematical or usual meaning of the operator, although it is strongly recommended. For example, a class that overloads operator+ to actually subtract or that overloads operator== to fill the object with zeros, is perfectly valid, although using such a class could be challenging.

我们使用这种 操作符重载 应该尽量符合数学规律,让我们用起来更加方便,就是这个样子。

The parameter expected for a member function overload for operations such as operator+ is naturally the operand to the right hand side of the operator. This is common to all binary operators (those with an operand to its left and one operand to its right). But operators can come in diverse forms. Here you have a table with a summary of the parameters needed for each of the different operators than can be overloaded (please, replace @ by the operator in each case):

这里是有关操作符重载的有关规范化设计,在这里,需要详细看得这个表,一定要明确。

操作符重载

tice that some operators may be overloaded in two forms: either as a member function or as a non-member function: The first case has been used in the example above for operator+. But some operators can also be overloaded as non-member functions; In this case, the operator function takes an object of the proper class as first argument.

注意,有些操作符可以被构成两种形式,一个是作为成员函数,另一种是作为非成员函数,这两种操作是你需要所明确的。

非成员函数的例子:

// non-member operator overloads
#include <iostream>
using namespace std;

class CVector {
  public:
    int x,y;
    CVector () {}
    CVector (int a, int b) : x(a), y(b) {}
};


CVector operator+ (const CVector& lhs, const CVector& rhs) {
  CVector temp;
  temp.x = lhs.x + rhs.x;
  temp.y = lhs.y + rhs.y;
  return temp;
}

int main () {
  CVector foo (3,1);
  CVector bar (1,2);
  CVector result;
  result = foo + bar;
  cout << result.x << ',' << result.y << '\n';
  return 0;
}

它相比于成员函数,在函数声明上,传递的参数上,都有很多不同,对于我来说,这样写起来更好。

class CVector {
  public:
    int x,y;
    CVector () {};
    CVector (int a,int b) : x(a), y(b) {}
    CVector operator + (const CVector&);
};

CVector CVector::operator+ (const CVector& param) {
  CVector temp;
  temp.x = x + param.x;
  temp.y = y + param.y;
  return temp;
}

这个就是成员函数,可以两者对比一下其区别,还是很好理解的,

The keyword this

The keyword this represents a pointer to the object whose member function is being executed. It is used within a class’s member function to refer to the object itself.

One of its uses can be to check if a parameter passed to a member function is the object itself. For example:

它的用途之一是检查传递给成员函数的参数是否是对象本身。

举个例子:

// example on this
#include <iostream>
using namespace std;

class Dummy {
  public:
    bool isitme (Dummy& param);
};

bool Dummy::isitme (Dummy& param)
{
  if (&param == this) return true;
  else return false;
}

int main () {
  Dummy a;
  Dummy* b = &a;
  if ( b->isitme(a) )
    cout << "yes, &a is b\n";
  return 0;
}

在这里 a 是这个类的对象,而我们把这个对象传递给了这个对象的成员函数,这个逻辑是你需要清楚明确的。

也可以通过这个来进行有关操作符重载,程序如下:

CVector& CVector::operator= (const CVector& param)
{
  x=param.x;
  y=param.y;
  return *this;
}

In fact, this function is very similar to the code that the compiler generates implicitly for this class for operator=.

这个this来返回这个成员本身,所以说this这个关键字就代表其成员本身,这种操作是你需要明确的。

Static members

A class can contain static members, either data or functions.

A static data member of a class is also known as a “class variable”, because there is only one common variable for all the objects of that same class, sharing the same value: i.e., its value is not different from one object of this class to another.

For example, it may be used for a variable within a class that can contain a counter with the number of objects of that class that are currently allocated, as in the following example:

// static members in classes
#include <iostream>
using namespace std;

class Dummy {
  public:
    static int n;
    Dummy () { n++; };
};

int Dummy::n=0;

int main () {
  Dummy a;
  Dummy b[5];
  cout << a.n << '\n';
  Dummy * c = new Dummy;
  cout << Dummy::n << '\n';
  delete c;
  return 0;
}

结果:

6
7

说明:

注意,这个类的构造器不需要传递任何参量,所以,只要一声明好就构造完成,而每次构造都n++,对于静态变量,前面我们已经讲过,默认的初始值为0,这样就能很好地实现有关操作,这是你需要明确的。

In fact, static members have the same properties as non-member variables but they enjoy class scope. For that reason, and to avoid them to be declared several times, they cannot be initialized directly in the class, but need to be initialized somewhere outside it. As in the previous example:
int Dummy::n=0;

静态成员和非成员变量有着很多相同的特征只是它的作用域关于类的,基于这,要避免它们被声明多次,它们不能在类中直接被初始化(因为共享的,声明一次那么就改变一次共享个鸟),我们可以在类外面,通过类的方式而非对象的方式来修改其静态变量,这是需要你明确的。

它也可以被直接输出,这种是你要明确的。

cout << a.n;
cout << Dummy::n;

Const member functions

When an object of a class is qualified as a const object:
const MyClass myobject;

The access to its data members from outside the class is restricted to read-only, as if all its data members were const for those accessing them from outside the class. Note though, that the constructor is still called and is allowed to initialize and modify these data members:

一旦申请个常量对象,那么其中的数据被设定为“只读”,你只能读取,无法修改其数据,这种概念是很好理解的。

// constructor on const object
#include <iostream>
using namespace std;

class MyClass {
  public:
    int x;
    MyClass(int val) : x(val) {}
    int get() {return x;}
};

int main() {
  const MyClass foo(10);
// foo.x = 20;            // not valid: x cannot be modified
  cout << foo.x << '\n';  // ok: data member x can be read
  return 0;
}

结果:10

The member functions of a const object can only be called if they are themselves specified as const members; in the example above, member get (which is not specified as const) cannot be called from foo. To specify that a member is a const member, the const keyword shall follow the function prototype, after the closing parenthesis for its parameters:
int get() const {return x;}
注意,对于其函数,你必须要制定const类型,如果不指定编译器不会通过的。

int get() const {return x;}        // const member function
const int& get() {return x;}       // member function returning a const&
const int& get() const {return x;} // const member function returning a const& 

看上面的,返回的如果是常类型则要设置好const

You may think that anyway you are seldom going to declare const objects, and thus marking all members that don’t modify the object as const is not worth the effort, but const objects are actually very common. Most functions taking classes as parameters actually take them by const reference, and thus, these functions can only access their const members:

常量对象实际上应用的非常普遍,大多数传递类的函数,其传递的参数都设计为静态的参数,因此,这些函数仅仅能允许那些它们的常量成员。

// const objects
#include <iostream>
using namespace std;

class MyClass {
    int x;
  public:
    MyClass(int val) : x(val) {}
    const int& get() const {return x;}
};

void print (const MyClass& arg) {
  cout << arg.get() << '\n';
}

int main() {
  MyClass foo (10);
  print(foo);

  return 0;
}

在这里,我们并非设计一个常量对象,而是其类内部的方法是静态的。当然,在这里,函数的返回值并不一定是静态的。

Member functions can be overloaded on their constness: i.e., a class may have two member functions with identical signatures except that one is const and the other is not: in this case, the const version is called only when the object is itself const, and the non-const version is called when the object is itself non-const.

// overloading members on constness
#include <iostream>
using namespace std;

class MyClass {
    int x;
  public:
    MyClass(int val) : x(val) {}
    const int& get() const {return x;}
    int& get() {return x;}
};

int main() {
  MyClass foo (10);
  const MyClass bar (20);
  foo.get() = 15;         // ok: get() returns int&
// bar.get() = 25;        // not valid: get() returns const int&
  cout << foo.get() << '\n';
  cout << bar.get() << '\n';

  return 0;
}

执行结果:15 20

这里使用int &来返回对象的成员,然后为其赋值,达到修改其成员的目的。

Class templates

Just like we can create function templates, we can also create class templates, allowing classes to have members that use template parameters as types. For example:

就像我们创造函数模版一样,我们也可以创造一个类模版,允许类可以使用模版中的参数作为其类型的。

template <class T>
class mypair {
    T values [2];
  public:
    mypair (T first, T second)
    {
      values[0]=first; values[1]=second;
    }
};

The class that we have just defined serves to store two elements of any valid type. For example, if we wanted to declare an object of this class to store two integer values of type int with the values 115 and 36 we would write:

mypair<int> myobject (115, 36);

我们可以设置好其传入的值的类型,在我们的类中的构造器造就设置好了。

mypair<double> myfloats (3.0, 2.18);

// class templates
#include <iostream>
using namespace std;

template <class T>
class mypair {
    T a, b;
  public:
    mypair (T first, T second)
      {a=first; b=second;}
    T getmax ();
};

template <class T>
T mypair<T>::getmax ()
{
  T retval;
  retval = a>b? a : b;
  return retval;
}

int main () {
  mypair <int> myobject (100, 75);
  cout << myobject.getmax();
  return 

Notice the syntax of the definition of member function getmax:

template <class T>
T mypair<T>::getmax ()

Confused by so many T’s? There are three T’s in this declaration: The first one is the template parameter. The second T refers to the type returned by the function. And the third T (the one between angle brackets) is also a requirement: It specifies that this function’s template parameter is also the class template parameter.

注意,该成员函数的返回类型也是T,这个是你所需要明确的。

##Template specialization

It is possible to define a different implementation for a template when a specific type is passed as template argument. This is called a template specialization.

当一个专门的类型被作为模版参数传递时,可以为模板定义不同的实现,这成为模版专门化。

For example, let’s suppose that we have a very simple class called mycontainer that can store one element of any type and that has just one member function called increase, which increases its value. But we find that when it stores an element of type char it would be more convenient to have a completely different implementation with a function member uppercase, so we decide to declare a class template specialization for that type:

  // template specialization
#include <iostream>
using namespace std;

// class template:
template <class T>
class mycontainer {
    T element;
  public:
    mycontainer (T arg) {element=arg;}
    T increase () {return ++element;}
};

// class template specialization:
template <>
class mycontainer <char> {
    char element;
  public:
    mycontainer (char arg) {element=arg;}
    char uppercase ()
    {
      if ((element>='a')&&(element<='z'))
      element+='A'-'a';
      return element;
    }
};

int main () {
  mycontainer<int> myint (7);
  mycontainer<char> mychar ('j');
  cout << myint.increase() << endl;
  cout << mychar.uppercase() << endl;
  return 0;
}

看这个代码,你就能很好理解,我们可以为其中一个指定的数据类型提供一个专门的特殊化的解决方案,而一般的就来处理其余的类型。

This is the syntax used for the class template specialization:
template <> class mycontainer <char> { ... };

template <class T> class mycontainer { ... };
template <> class mycontainer <char> { ... }

The first line is the generic template, and the second one is the specialization.

第一个是一般化形式,第二个是模版的专门化形式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值