C++设计一个不含指针的类

970 阅读7分钟

本文已参与新人创作礼」活动,一起开启掘金创作之路。

原文链接:blog.csdn.net/roufoo/arti… C++设计一个不含指针的类相对设计一个含指针的类来说简单一些,因为它不需要考虑一下三大因素(也叫Big Three): 析构函数(destructor) 拷贝构造函数(copy constructor) 拷贝赋值函数(copy assignment operator) 如果我们定义一个类的时候没有给出这3个函数,那么C++的编译器会自动生成四个缺省函数如下:

A(void); // 缺省构造函数 A(const A &a); // 缺省拷贝构造函数 ~A(void); // 缺省析构函数 A & operate =(const A &a); // 缺省拷贝赋值函数 1 2 3 4 这些函数都是基于memberwise copy - 因为没有指针,所以不会涉及到同一块内存被多个对象指向的问题。析构的时候也不需要考虑内存的操作。

举例complex类如下:

class complex //class head { //class body public: complex (double r = 0, double i = 0): re (r), im (i) { } complex& operator += (const complex&); double real () const { return re; } double imag () const { return im; } private: double re, im; friend complex& __doapl (complex *, const complex&); }; 1 2 3 4 5 6 7 8 9 10 11 12 这里有几个需要注意的地方:

real()和imag()在类的体内定义,则自动成为inline函数。如果在体外定义,则需要显式声明inline才会成为inline函数。

friend函数本身不是类的一部分,friend是指此函数可以自由访问该类的private成员。friend也可以用在类上面,一个类的friend类的object可以访问该类的private成员。注意: 同一个类的各个object互为friend,这也是为什么拷贝构造函数和赋值构造函数可以实现的基础。

friend函数有什么好处呢?因为friend函数不需要通过class来访问,比用class函数来做效率更高。

complex定义了自己的缺省构造函数。 complex (double r = 0, double i = 0): re (r), im (i) { } 1 所谓缺省构造函数是指对象的创建不需要参数就可调用的构造函数。C++标准规定,如果构造函数没有参数,或者构造函数的所有参数都有缺省值,则算作缺省构造函数。

如果complex没有定义自己的缺省构造函数,C++编译器会自动给它生成一个缺省构造函数类似于 complex() {} 注意该函数什么也不做。

如果complex的缺省构造函数为 complex(double r=0, double i=0): re®, im(i) {}, 并且没有其他缺省构造函数,代码 complex c1; 会调用该构造函数,并用re和im的缺省参数。

如果complex的构造函数为 complex(double r, double i): re( r ), im( i ) {}, 并且没有其他缺省构造函数,代码 complex c1; 会编译出错,因为编译器不知道把什么值赋给re和im。

如果complex的缺省构造函数为 complex() {}, 并且没有其他缺省构造函数,代码 complex c1; 会调用该缺省构造函数。

如果complex 有两个缺省构造函数, complex() {} complex(double r=0, double i=0): re( r ), im( i ) {} 代码 complex c1; 编译会出错,因为编译器不知道调用那个缺省构造函数。

如果complex有以下两个构造函数,注意第一个为缺省构造函数,第二个不是。它们可以共存。 complex() {} complex(double r, double i): re( r ), im( i ) {} 代码 complex c1; 编译会通过,编译器会采用complex() {}作为缺省构造函数。

如果complex没有定义拷贝构造函数,那么 complex c1=complex(); 和 complex c1 = c2; 都会调用complex的缺省拷贝构造函数(也就是memberwise copy)。注意第一个例子里面的complex()会导致调用缺省构造函数生成一个complex的临时对象,然后代码再调用comlex的缺省拷贝构造函数进行memberwise copy。第二个例子则只需调用缺省拷贝构造函数一次。

如果complex没有定义拷贝赋值函数,那么 c1 = c2; 会调用complex的缺省拷贝赋值函数。

下面几种写法要特别注意它们的区别: complex c1(); 声明一个名为c1的函数, 该函数返回complex类型。注意这里不是创建complex 类的对象! 切记!!! complex c1; //创建一个complex的一个名为c1的obj, 并且会调用complex 类中的缺省构造函数,其缺省参数为(0,0). complex(); //创建一个complex的临时对象,此处会调用complex 类中的缺省构造函数,同样,int()也是创建一个int的临时对象 complex c1=complex(); //创建一个complex的临时对象,并赋给c1,此处会调用缺省构造函数和缺省拷贝构造函数 complex c1=complex(3.0, 4.0); ** //创建一个complex的临时对象,并赋给c1,此处会调用构造函数和缺省拷贝构造函数** 注意这里也可以写成complex c1(3.0, 4.0), 会调用构造函数。 complex *p=new complex();//创建一个complex的obj,这里会调用complex类中的缺省构造函数,并用指针p指向它。 注意,这两种写法都可以: complex c1 = complex(3.0, 4.0); //构造函数和缺省拷贝构造函数 complex c1(3.0, 4.0); //构造函数only ?

complex重载了+=操作符。操作符重载可以看成是一个特殊的函数,给C++编程带来很大便利。 操作符重载可以是类成员函数,也可以是非类成员函数。如果是object自身与complex的其它object相加,可写成类成员函数,如上面的这种情况; 但如果不是object自身与complex其他object相加,则不能写成类成员函数。

如果是成员函数的话,默认第一个参数是this指针,通常不写。注意:操作符重载一定是作用在左边的操作符。

上面operator+重载函数参数采用传引用。 对于函数入口参数,尽量用传引用,因为传值的话,value会放进stack,应该尽量少用。 另外,对于函数返回值也是尽量返回reference,但如果函数返回的是在栈上分配的一个local变量或object,则不能返回reference,因为该local变量或obj已经被删除。

上面operator+的入口参数加了const。对于函数入口参数,如果函数不会改变这个参数,则该参数可以加const。 另外,如果某类函数不会改变函数的数据成员,则可以在函数名后加const,比如上面的real()和imag()函数。

C++ 的构造函数和析构函数都没有返回值!切记!

拷贝构造函数的参数一定要加&(即传引用),如果是传值,形参复制到实参的时候又会调用拷贝构造函数,这样就形成永无止境的递归调用而导致栈溢出。

一个Complex类的实现例子如下:

#include #include using namespace std;

class MyComplex { public:

MyComplex(double re = 0, double im = 0) : real(re), imag(im) {}
MyComplex(const MyComplex &c) : real(c.real), imag(c.imag) {}
MyComplex & operator = (const MyComplex &c) { real = c.real; imag = c.imag; }
MyComplex & operator += (const MyComplex &c);
MyComplex & operator -= (const MyComplex &c);
MyComplex & operator *= (const MyComplex &c);
MyComplex & operator /= (const MyComplex &c);
MyComplex operator + (const MyComplex &c);
MyComplex operator - (const MyComplex &c);
MyComplex operator * (const MyComplex &c);
MyComplex operator / (const MyComplex &c);

double get_real() { return real; };
double get_imag() { return imag; };

private: double real, imag; friend ostream & operator<<(ostream &out, const MyComplex &c); };

MyComplex& MyComplex::operator += (const MyComplex &c) { this->real += c.real; this->imag += c.imag; return *this; }

MyComplex& MyComplex::operator -= (const MyComplex &c) { this->real -= c.real; this->imag -= c.imag; return *this; }

MyComplex& MyComplex::operator *= (const MyComplex &c) { // this->real = this->real * c.real - this->imag * c.imag; double re = this->real * c.real - this->imag * c.imag; this->imag = this->real * c.imag + this->imag * c.real; this->real = re; return *this; }

MyComplex& MyComplex::operator /= (const MyComplex &c) { MyComplex temp(c.real, -c.imag); MyComplex numerator = *this * temp; double denominator = c.real * c.real + c.imag * c.imag; //MyComplex res = MyComplex(numerator.real / denominator, numerator.imag / denominator); this->real = numerator.real / denominator; this->imag = numerator.imag / denominator; return *this; }

MyComplex MyComplex::operator + (const MyComplex &c) { MyComplex res(this->real + c.real, this->imag + c.imag); return res; }

MyComplex MyComplex::operator - (const MyComplex &c) { MyComplex res(this->real - c.real, this->imag - c.imag); return res; }

MyComplex MyComplex::operator * (const MyComplex &c) { MyComplex res(this->real * c.real - this->imag * c.imag, this->real * c.imag + this->imag * c.real); return res; }

MyComplex MyComplex::operator / (const MyComplex &c) { MyComplex temp(c.real, -c.imag); MyComplex numerator = *this * temp; double denominator = c.real * c.real + c.imag * c.imag; MyComplex res = MyComplex(numerator.real / denominator, numerator.imag / denominator); return res; }

ostream & operator<<(ostream &out, const MyComplex &c) { out << "(" << c.real << "," << c.imag << ")"; return out; }

int main() { complex c1(3.6, 7.2), c2(7.1, 9.5); MyComplex myc1(3.6, 7.2), myc2(7.1, 9.5); cout << "c1 = " << c1 << endl; cout << "c2 = " << c2 << endl; cout << "myc1 = " << myc1 << endl; cout << "myc2 = " << myc2 << endl;

complex<double> d1 = c1 + c2;
MyComplex myd1 = myc1 + myc2;
cout << "d1 = " << d1 << endl;
cout << "myd1 = " << myd1 << endl;

complex<double> e1 = c1 - c2;
MyComplex mye1 = myc1 - myc2;
cout << "e1 = " << e1 << endl;
cout << "mye1 = " << mye1 << endl;

complex<double> f1 = c1 * c2;
MyComplex myf1 = myc1 * myc2;
cout << "f1 = " << f1 << endl;
cout << "myf1 = " << myf1 << endl;

complex<double> g1 = c1 / c2;
MyComplex myg1 = myc1 / myc2;
cout << "g1 = " << g1 << endl;
cout << "myg1 = " << myg1 << endl;

c1 += c2;
myc1 += myc2;
cout << "c1 = " << c1 << endl;
cout << "myc1 = " << myc1 << endl;

c1 -= c2;
myc1 -= myc2;
cout << "c1 = " << c1 << endl;
cout << "myc1 = " << myc1 << endl;

c1 *= c2;
myc1 *= myc2;
cout << "c1 = " << c1 << endl;
cout << "myc1 = " << myc1 << endl;

c1 /= c2;
myc1 /= myc2;
cout << "c1 = " << c1 << endl;
cout << "myc1 = " << myc1 << endl;

return 0;

}

———————————————— 版权声明:本文为CSDN博主「纸上得来终觉浅 绝知此事要躬行」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。