C++ class without pointer

  •   写在前面

终于放假了,可以自由安排时间了,既然已经决定放弃做实验,不是不想坚持,更想正常毕业,可是这个实验偶然性太大,最主要的是不可重现,所以也没意义,也没有理论支持,当然角度新,如果测量出一个好 的实验效果,或许我也通过答辩而顺利毕业,可我不想为了毕业而毕业,再说都做了一年多了,花了大量时间在上面,过去几个月一直焦心毕业问题,投入的时间更多,还放弃了秋招,现在,想想实在是不明智的选择,现在,我只想做我自己想做的事,be a game changer.从今天晚上开始,我先简单复习C++,虽然时隔比较久了,之前也只是简单的过了过基础,我想我还是可以的。还是从基础开始,我坚一切知识,基础都是非常重要的,勿在浮沙筑高台。

  • Object Oriented

class 的分类:带指针的class和不带指针的class,

class 的声明

       

这里有一个inline的概念,写在类里面的默认为inline,写在class外部的只有声明,为inline才有可能编译成Inline,最终编译时是否为inline,由编译器决定。Inline函数速度快.

public:

private:所有数据都应放在private,函数根据是否想要被外界调

使用对象

×   √ 

  • 构造函数:

想要创建一个对象,会自动调用的函数就是构造函数,如上,构造函数与类同名,没有返回类型,不需要有,因为构造函数就是要来创建对象的,此处对象就是complex,上面定义的构造函数使用了列表初始化,并且这种初始化只有构造函数才有,其它函数是没有的,并且给出了default argument

这里多说一些,一个数值的设定有两个阶段,一个是初始化,一个是后面再赋值(assign),所以列表初始化和在函数体赋值是不同的。

与构造函数对应是析构函数,但是这个例子中不需要写析构函数,前面提到过class的经典分类,不带指针的class多半需用写析构函数

构造函数可以有多个-overloading,但是存在歧义的不可以,如下:

complex() :re(0), im(0) {}//不可以,ambiguous

如下面的对象c2,都没有给参数,编译器发现 可以调用上面的,但是编译器也发现class中的构造函数虽然有参数,但是有默认值,也可以调用,因此编译器就不知调用哪个了

创建对象

       

构造函数放在private中,即不允许外界调用构造函数

class A {
public:
    static A& getInstance();
private:
    A();
    A(const A& rhs);

};

A& A::getInstance()
{
    static A a;
    return a;
}

外界只能用一份A,即static的部分,外界用的时候不能使用传统的调用方式,只能通过getInstance()函数

  •  参数传递与返回值
double real()const { return re; }
double imag()const { return im; }

看上面的代码,都是const型的,因为我不需要改变数据,只是将数据拿出来,看下面两种情况

A.        B.

如果我的函数没用定义为const类型,B中的调用就是错误的,使用者本想,我只是返回数据,并不改变,所以创建了一个常对象,但是由于函数没有定义为const,所以就会出现调用错误。

  • 参数传递:

pass by value  vs pass by reference(to const)

pass by value 就是整包都传过去,数据多大就传多大,传的数据是压到static栈中的,本例中,传的是double,是4个字节,传的就是4个字节,若传的数据很大呢,效率就低,所以尽量不要pass by value,  可以pass by reference ,reference在底部就是指针,

 1 ostream& operator <<(ostream& os, const complex& x)
 2 {
 3     return os << ‘(‘ << real(x) << ‘,‘ << imag(x) << ‘)‘;
 4 }
 5 int main()
 6 {
 7     complex c1(2, 1);
 8     complex c2;
 9     c2 += c1;
10     cout << c2;
11 }

第7,8行会调用构造函数,通过pass by lalue的方式,第9行会调用1-4行的函数,pass by reference的方式。返回值的传递也尽量pass by reference

friend complex& __doapl(complex*, const complex&);//return value :pass by reference

后面会给出上面函数的detail

下面看一种情况,为什么可以这样使用

int func(const complex& param)
    {
        return param.re + param.im;
    }
//用法
complex c3;
c3.func(c1);

可以这样理解:相同class的各个objects 互为friends

class body外的各种定义什么情况下可以pass by value,什么情况下可以pass by reference

首先看看什么情况不能return by reference

 1 inline complex&
 2 __doapl(complex* ths, const complex& r)
 3 {
 4     ths->re += r.re;//第一参数将会被改动
 5     ths->im += r.im;//第二参数不会被改动
 6     return *ths;
 7 }
 8 inline complex&
 9 complex::operator+=(const complex& r)
10 {
11     return __doapl(this, r);
12 }

这里,函数将结果放在第一个参数中,有专门的存储的空间,还有一种情况就是函数专门开辟一个空间存放结果,如果只是

return c1 + c2;

这时,是一个临时开辟的local变量存储c1+c2的结果,函数结束,这个临时变量的生命就结束了,这时,就不能返回reference

  • 操作符重载(-1,成员函数) this

想象我们在数学中的复数,有哪些操作,比如相加,复数+复数,复数+实数,复数+纯虚数,

继续看上面代码,编译器看到c2+=c1,就会把操作符作用到左边c2身上,上面的inline complex& complex::operator+=(const complex& r){}相当于

inline complex& complex::operator(this,const complex& r){}

为什么可以这样呢,这就是上面辩题中写道的操作符重载之成员函数,因为所有成员函数带有一个隐藏的参数this,谁调用这个函数谁就是this,这里this是c2,

Note:this不可以写在参数列表中,用可以像函数体中那样用,return __doapl(this,r);

  • return by reference 语法分析

继续看上面的代码,看函数定义时的返回类型是complex&,函数体内返回的却是*ths,这样是正确的,因为,传递者无需知道接收者是以reference形式接收

class body之外的函数定义

operator overloading(操作符重载-2,非成员函数)无this

考虑到用户的行为,定义了三种+ 形式

 1 inline complex
 2 operator +(const complex& x, const complex& y)
 3 {
 4     return  complex(real(x) + real(y), imag(x) + imag(y));
 5 }
 6
 7 inline complex
 8 operator +(const complex& x, double y)
 9 {
10     return complex(real(x) + y, imag(y));
11 }
12
13 inline complex
14 operator +(double x, const complex& y)
15 {
16     return complex(x + real(y), imag(y));
17 }

如上,对于上面的操作符重载,没有this pointer,因为是全域函数,不再是成员函数

  • temp object (临时对象)tempname()

再看上面的代码,return by value,对于上面的代码,绝不可以return by reference,因为他们返回的一定是local object,因为加的结果是函数临时创建的,函数结束,临时变量死亡,

解释一下:tempname(),此处是complex(),就是创建临时对象,tempname()类似于Int(),

operator +(const complex& x)
{
    return x;
}

inline complex
operator -(const complex& x)
{
    return complex(-real(x), -imag(x));
}
//使用
{
    complex c1(2, 1);
    complex c2;
    cout << -c1;
    cout << +c1;
}

这里是return  by value,这里可是return by reference,因为,这里结果没有改变,也没有创建新的临时对象,所以是可以return by reference的。

接下来还是操作符重载,考察的东西一样,语法上没有新的了,

inline bool
operator ==(const complex& x, const complex& y)
{
    return real(x) == real(y) && imag(x) == iamg(y);
}
inline bool
operator ==(const complex& x, double y)
{
    return real(x) == y && iamg(x) == 0;
}

inline bool
operator ==(double x, complex& y)
{
    return x == real(y) && iamg(y) == 0;
}

inline bool
operator !=(const complex& x, complex& y)
{
    return real(x) != real(y) || imag(x) != imag(y);
}

inline bool
operator !=(const complex& x, double y)
{
    return real(x) != y || iamg(x) != 0;
}

inline bool
operator !=(double x, complex& y)
{
    return x != real(y) || iamg(y) != 0;
}

inline complex
conj(const complex& x)
{
    return complex(real(x), -imag(y));
}

ostream& operator <<(ostream& os, const complex& x)
{
    return os << ‘(‘ << real(x) << ‘,‘ << imag(x) << ‘)‘;
}

//使用
{
cout << conj(c1);
cout << c1 << conj(c1);
}

"<<"作用在左边,这里绝不能写成成员函数,必须写成全域函数。os也不可是const的,因为每往cout中放入“东西”的时候都是在改变os中的内容,若将返回类型 ostream& ,改为 void 可以吗?

如果只是输出一个是可以的(上面第一处使用),如果连续输出是不可以的(第二处使用),

下面是完整的代码(还有很多操作没写,但写的已经涵盖了这种类型的class的几乎所有语法,有时间再补全):

  1 #pragma once
  2 #ifndef __COMPLEX__
  3 #define __COMPLEX__
  4
  5 class complex {
  6 public:
  7     complex(double r = 0, double i = 0) :re(r), im(i) {}//construct function
  8     //complex() :re(0), im(0) {}//不可以,ambiguous
  9     complex& operator +=(const complex&);//two choices,member func or non-member func,
 10     //here is member func,do not need to change the value,so is const
 11     double real()const { return re; }
 12     double imag()const { return im; }
 13     int func(const complex& param)
 14     {
 15         return param.re + param.im;
 16     }
 17 private:
 18     double re, im;
 19     friend complex& __doapl(complex*, const complex&);//return value :pass by reference
 20
 21 };
 22
 23 inline complex&
 24 __doapl(complex* ths, const complex& r)
 25 {
 26     ths->re += r.re;//第一参数将会被改动
 27     ths->im += r.im;//第二参数不会被改动
 28     return *ths;
 29
 30 }
 31 inline complex&
 32 complex::operator+=(const complex& r)//the right is not change,so is const,the left
 33 {//has already existed,so return by reference
 34     return __doapl(this, r);
 35 }
 36 inline double
 37 real(const complex& x)
 38 {
 39     return x.real();
 40 }
 41 inline double
 42 imag(const complex& x)
 43 {
 44     return x.imag();
 45 }
 46 //"+"has more than one cases,so set it as the non-member func
 47 inline complex
 48 operator +(const complex& x, const complex& y)
 49 {//the sum result will be put in a local variable,so return by value
 50     return  complex(real(x) + real(y), imag(x) + imag(y));
 51 }
 52
 53 inline complex
 54 operator +(const complex& x, double y)
 55 {
 56     return complex(real(x) + y, imag(y));
 57 }
 58
 59 inline complex
 60 operator +(double x, const complex& y)
 61 {
 62     return complex(x + real(y), imag(y));
 63 }
 64 inline complex
 65 operator +(const complex& x)
 66 {
 67     return x;
 68 }
 69
 70 inline complex
 71 operator -(const complex& x)
 72 {
 73     return complex(-real(x), -imag(x));
 74 }
 75
 76 inline bool
 77 operator ==(const complex& x, const complex& y)
 78 {
 79     return real(x) == real(y) && imag(x) == imag(y);
 80 }
 81 inline bool
 82 operator ==(const complex& x, double y)
 83 {
 84     return real(x) == y && imag(x) == 0;
 85 }
 86
 87 inline bool
 88 operator ==(double x, complex& y)
 89 {
 90     return x == real(y) && iamg(y) == 0;
 91 }
 92
 93 inline bool
 94 operator !=(const complex& x, complex& y)
 95 {
 96     return real(x) != real(y) || imag(x) != imag(y);
 97 }
 98
 99 inline bool
100 operator !=(const complex& x, double y)
101 {
102     return real(x) != y || imag(x) != 0;
103 }
104
105 inline bool
106 operator !=(double x, complex& y)
107 {
108     return x != real(y) || imag(y) != 0;
109 }
110
111 inline complex
112 conj(const complex& x)
113 {
114     return complex(real(x), -imag(x));
115 }
116
117 #endif

测试代码有时间再补

原文地址:https://www.cnblogs.com/Holly-blog/p/8411091.html

时间: 2024-10-21 09:01:33

C++ class without pointer的相关文章

CSS中cursor的pointer 与 hand

附:cursor属性收集 光标类型   CSS 十字准心 cursor: crosshair; 手 cursor: pointer; cursor: hand; 写两个是为了照顾IE5,它只认hand. 等待/沙漏 cursor: wait; 帮助 cursor: help; 无法释放 cursor: no-drop; 文字/编辑 cursor: text; 可移动对象 cursor: move; 向上改变大小(North)   cursor: n-resize; 向下改变大小(South)  

138 Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list. copy 的题多用hashmap, 难点在于如何让遍历, 如何构建新的节点间的关系. /** * Definition for singly-linked list wit

c++ array and pointer

pointer to const object and const pointer, 1.指向常量对象的指针,意思是指针所指向的 对象内容不能变(不能够通过指针赋值). 2.常量指针,意思是指针内容不能变,指向对象a就不能改为指向对象b(指针不能指向别处).(简单来说就是const挨着哪个近,哪个就不能变.) pointer to const object: const double *cptr; // cptr may point to a double that is const const

iOS-Tagged Pointer对象-注意事项

一,2013年9月,苹果推出了iPhone5s,与此同时,iPhone5s配备了首个采用64位架构的A7双核处理器,为了节省内存和提高执行效率,苹果提出了Tagged Pointer的概念. 对于64位程序,引入Tagged Pointer后,相关逻辑能减少一半的内存占用,并有3倍的访问速度提升,以及100倍的创建,销毁速度提升. 二,当8字节可以承载用于表示的数值时,系统就会以Tagged Pointer的方式生成指针,如果8字节承载不了时,则又用以前的方式来生成普通的指针. 三,Tagged

LeetCode138 Copy List with Random Pointer(深度复制带有随机指针的链表) Java题解

题目: A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list. 解题: 这题是要复制一个链表,这个链表比普通的链表多一个指针,这个指针可以指向任意地方,可以为空也可以为链表中的任一个节点,今天中午的时候我同学和我说起这题,当时问

Codeforces Gym 100187M M. Heaviside Function two pointer

M. Heaviside Function Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100187/problem/M Description Heaviside function is defined as the piecewise constant function whose value is zero for negative argument and one for non-negat

C++中单项链表的结点删除问题——为什么我的链表编译能过,但是运行的时候显示:*** Error in `./list&#39;: free(): invalid pointer: 0x08ba20cc *** 已放弃 (核心已转储)

1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 struct student{ 6 int my_id; 7 char name[20]; 8 int my_age; 9 int my_score; 10 student *next = nullptr; 11 student() = default; 12 student(int id,const char *n,int age,int sco

[LeetCode]Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list. 利用hashMap存储,原始的node作为key,new的node作为value,这样就建立了新旧链表的以一一对应关系: /** * Definition for sing

C++中Reference与指针(Pointer)的使用对比

我们已经知道在C++中,对象变量直接存储的是对象的值.这是与Java不同的,在Java中对象变量存储的是一个地址,该地址指向对象值实际存储的地方.有时在C++中也需要实现这样的布置,这就用到了指针pointer.在 C++中,一个指向对象的变量叫做指针.如果T是一种数据类型,则 T* 是指向这种数据类型的指针. 这里重点介绍C++与Java的不同,要详细了解C++中指针的使用 就像 Java中一样,一个指针变量可以被初始化为空值 NULL,另外一个指针变量的值,或者一个调用new生成的新对象:

【LeetCode】Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointer which could point to any node in the list or null. Return a deep copy of the list. 思路:第一遍正常复制链表,同时用哈希表保存链表中原始节点和新节点的对应关系,第二遍遍历链表的时候,再复制随机域. 这是一种典型的空间换时间的做法,n个节点,需要大小为O(n