浅谈结构体构造函数用法

1.构造函数的优势

众所周知,在结构体内部可以定义变量、函数等,但结构体内部的变量有一个特点:无法被初始化。因此我们需要初始化变量时可以通过函数实现。

struct student{
    string name;
    int score;
    void pre(){
        name="Tom";
        score=4;
    }
};
int main(){
    student a;
    a.pre();
    printf("%d\n",a.score);  
}

但每定义一个student类型的变量时,我们就需要调用pre函数一次,操作略为繁琐。因此我们可以采用构造函数。

2.构造函数的写法

构造函数是一类较为特别的成员函数,它必须先声明在结构体的内部,其函数名与该结构体类型的名字一样,如此处结构体类型名为student,则构造函数的名字便为student。另外,构造函数没有返回值,不需要用户调用(用户也无法调用),而是在创建对象时自动执行

struct student{
    string name;
    int score;
    student(){
        name="Tom";
        score=6;
    }
};
int main(){
    student a;
    printf("%d\n",a.score);  
}

构造函数可以与其他函数一样传入参数,根据参数来进行初始化。在调用时必须在定义结构体类型的变量时同时传入参数,故不能定义为student  a;student\;a;studenta

struct student{
    string name;
    int score;
    student(string s,int val){
        name=s;
        score=val;
    }
};
int main(){
    student a("Tom",5);
    printf("%d\n",a.score);  
}

有时参数可以不是通过我们手工输入,而是自动为其赋一个值作为参数,如下代码:

struct student{
    string name;
    int score;
    student(string s,int val=4){
        name=s;
        score=val;
    }
};
int main(){
    student a("Tom");
    printf("%d\n",a.score);  
}

此处构造函数的val已经被我们赋值为4,故在定义时不需传入val的参数。但如仍要传入,则最后以我们传入的参数为准,例:

struct student{
    string name;
    int score;
    student(string s,int val=4){
        name=s;
        score=val;
    }
};
int main(){
    student a("Tom",6);
    printf("%d\n",a.score); //输出6 
}

3.构造函数的初始化列表

构造函数在给成员变量赋值时,可以不把赋值操作写在函数体内部,而是把它们放到函数名与函数体之间,具体格式如下:

struct student{
    string name;
    int score;
    student(string s,int val):name(s),score(val){}
};
int main(){
    student a("Tom",6);
    printf("%d\n",a.score);  
}

在函数名之后用冒号引起,不同的成员变量之间用逗号隔开,每个成员变量用括号表示赋值。此种方法较为简便,被较多人采用。

注:给成员变量赋值时赋值顺序与构造函数中成员变量书写的顺序无关,而是与成员变量在结构体内被定义的顺序有关

struct student{
    string name;
    int score1,score2;
    student(int val):score2(val),score1(score2){}
};
int main(){
    student a(6);
    printf("%d %d\n",a.score1,a.score2);  
    //输出0 6
}

虽然在构造函数中score2的赋值操作写在了score1之前,但实际进行中先进行score1的赋值操作,此时score2未被赋值,因此score1得到的值是随机的。

4.构造函数的种类

构造函数的名称全部相同,所以区分不同的构造函数只能依靠参数的种类、数目。

struct student{
    int val1,val2;
    string s;
    student(int x){
        val1=x;
    } 
    student(int x,int y){
        val1=x;
        val2=y;
    }
    student(string s1){
    	s=s1;
    }
};
int main(){
    student a(1),b(1,2);
    printf("%d\n",a.val1);
    printf("%d\n",b.val2);
}

注意:在我们未定义构造函数的时候,系统会自动帮我们定义构造函数,此时的构造函数为空,没有参数也没有函数体,不执行任何操作。

<think>我们被要求回答关于C#结构体构造函数的问题。根据提供的引用资料,我们可以总结如下: 引用[1]提到:在C# 8.0及更高版本中,readonly结构体(readonly struct)的除构造函数外的其他实例成员都是隐式readonly的。这保证了结构体的状态不会被修改。 引用[2]展示了如何定义带构造函数结构体: ```csharp public struct NR_BCH_PROP { public long arfcn; public long center_freq; // 带参数的构造函数 public NR_BCH_PROP(long a, long b) { arfcn = a; center_freq = b; } } ``` 引用[3]和[4]则对比了结构体和类的构造函数在内存分配上的不同:结构体是值类型,即使使用new关键字,其构造函数也会被调用,但内存分配是由new操作符隐式处理的。 现在,我们根据这些引用信息来组织答案: # C# 结构体构造函数详解 在C#中,结构体(struct)是一种值类型,通常用于封装小型相关变量组。结构体可以包含构造函数,用于初始化其数据成员。下面详细介绍结构体构造函数的特性、使用方法和注意事项。 ## 1. 结构体构造函数的定义 结构体可以定义带参数的构造函数,用于初始化字段。例如: ```csharp public struct Point { public int X; public int Y; // 带参数的构造函数 public Point(int x, int y) { X = x; Y = y; } } ``` **重要规则**: - 必须显式初始化所有字段,否则编译错误 - 不能定义无参数构造函数(C# 10.0之前) - 不能为字段设置初始值(C# 10.0之前) ## 2. 结构体构造函数的调用 结构体构造函数通过`new`关键字调用,但内存分配机制与类不同: ```csharp Point p = new Point(10, 20); // 在栈上分配并调用构造函数 ``` 即使不使用`new`,结构体变量也存在(所有字段为默认值),但此时未调用构造函数。 ## 3. 只读结构体(readonly struct)的构造函数 C# 7.2引入只读结构体,其构造函数可以修改字段,但其他方法不能: ```csharp public readonly struct ImmutablePoint { public int X { get; } public int Y { get; } public ImmutablePoint(int x, int y) { X = x; Y = y; } } ``` 在C# 8.0+中,只读结构体的非构造函数成员隐式`readonly`[^1]。 ## 4. 与类构造函数的区别 | 特性 | 结构体构造函数 | 类构造函数 | |---------------------|------------------------------|--------------------------| | 无参构造函数 | C# 10.0前不允许定义 | 允许定义 | | 字段初始化 | C# 10.0前必须在构造函数中完成| 允许字段初始值设定项 | | 内存分配 | 栈或内联(通常) | 托管堆 | | `new`操作 | 非必须(但推荐) | 必须(引用类型) | ## 5. C# 10.0 的改进 C# 10.0 允许结构体: - 定义无参数构造函数 - 在声明时为字段设置初始值 ```csharp public struct Point { public int X = 1; // 允许字段初始化 public int Y = 1; public Point() {} // 允许无参构造函数(C# 10.0+) } ``` ## 6. 最佳实践 1. **小型数据**:结构体适合16字节以内的轻量数据 2. **不可变性**:优先设计为只读结构体 3. **构造函数**:始终通过构造函数完全初始化字段 4. **避免装箱**:注意值类型到引用类型的转换开销 > 结构体构造函数的核心作用:**保证创建的值具有确定的状态**。 §§相关问题§§ 1. C# 10.0 中结构体的无参构造函数有哪些使用限制? 2. 如何避免结构体在方法传递时产生装箱操作? 3. 只读结构体与普通结构体在性能上有何差异? </think> # C# 结构体构造函数详解 在C#中,结构体(struct)是值类型,其构造函数具有一些独特的行为和限制。理解这些特性对于正确使用结构体至关重要。 ## 一、基本结构体构造函数 结构体可以定义带参数的构造函数来初始化字段: ```csharp public struct Point { public int X; public int Y; // 带参数的构造函数 public Point(int x, int y) { X = x; // 必须初始化所有字段 Y = y; } } ``` **重要规则**: 1. 必须显式初始化所有字段(否则编译错误) 2. 不能定义无参数构造函数(C# 10.0之前) 3. 所有字段必须在构造函数中赋值后才能使用 ## 二、只读结构体构造函数 C# 7.2引入只读结构体(`readonly struct`),其构造函数行为有特殊规则: ```csharp public readonly struct ImmutablePoint { public int X { get; } public int Y { get; } public ImmutablePoint(int x, int y) { X = x; Y = y; } // C# 8.0+ 中非构造函数成员隐式只读 public double Distance => Math.Sqrt(X * X + Y * Y); } ``` - 保证结构体状态不会被修改[^1] - C# 8.0+ 中除构造函数外的成员隐式`readonly` ## 三、结构体与类构造函数的区别 | **特性** | **结构体(struct)** | **类(class)** | |------------------|----------------------------|------------------------| | 内存位置 | 栈或内联存储 | 托管堆 | | 默认构造函数 | 自动提供,不可自定义(10.0前)| 可自定义无参构造函数 | | `new`操作语义 | 调用构造函数并返回实例 | 分配内存+调用构造函数 | | 字段初始化要求 | 构造函数必须初始化所有字段 | 无此要求 | | 继承 | 不支持 | 支持 | 结构体构造函数在栈上分配内存,即使使用`new`关键字,内存分配也是隐式处理的[^3]: ```csharp Point p = new Point(10, 20); // 在栈上分配内存 ``` ## 四、C# 10.0 的改进 C# 10.0 解除了结构体的部分限制: ```csharp public struct Vector { public double X = 1; // 允许字段初始化 public double Y = 1; public Vector() {} // 允许无参构造函数 public Vector(double x, double y) { X = x; Y = y; } } ``` ## 五、静态构造函数 结构体可以包含静态构造函数,用于初始化静态字段: ```csharp public struct Temperature { public static double AbsoluteZero; static Temperature() { AbsoluteZero = -273.15; } } ``` 静态构造函数在首次访问类型时执行[^4]。 ## 六、最佳实践 1. **保持小型化**:结构体应小于16字节 2. **优先不可变性**:使用`readonly struct`设计 3. **显式初始化**:确保所有字段在构造函数中赋值 4. **值语义利用**:适合坐标、颜色等小型数据 5. **避免装箱**:注意值类型到引用类型的转换 > **关键原则**:结构体构造函数的核心作用是保证创建的值具有确定的状态,这是值类型可靠性的基础[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值