对于swift(14)构造函数感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解构造函数=default,并且为您提供关于c–使用SFINAE“重载”构造函数、c–错误:为“构造函数”属性指定
对于swift (14) 构造函数感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解构造函数=default,并且为您提供关于c – 使用SFINAE“重载”构造函数、c – 错误:为“构造函数”属性指定的参数数量错误、c# – 构造函数/析构函数链接错误、C#构造函数的宝贵知识。
本文目录一览:swift (14) 构造函数(构造函数=default)
类和结构体必须给他们的所有存储变量赋值,不允许类实例初始化完成后,还有变量没有被初始化,否则会不能通过编译。
你可以在构造函数中初始化一个存储型变量,也可以通过在定义时赋初始值的方法初始化变量。
struct Fahrenheit {
var temperature: Double
init() {
temperature = 32.0
}
}
var f = Fahrenheit()
println("The default temperature is \(f.temperature)° Fahrenheit")
// prints "The default temperature is 32.0° Fahrenheit"
下面的效果跟上例类似,明显的,下面的方法简单明了,如果每个实例的初始化的值是相同的,则在定义时赋初始值是推荐的
struct Fahrenheit {
var temperature = 32.0
}
初始化使用参数方式如下,可以有多个初始化,使用不同的参数名,下例是一个对温度不同的赋值方法:
struct Celsius {
var temperatureInCelsius: Double = 0.0
init(fromFahrenheit fahrenheit: Double) {
temperatureInCelsius = (fahrenheit - 32.0) / 1.8
}
init(fromKelvin kelvin: Double) {
temperatureInCelsius = kelvin - 273.15
}
}
let boilingPointOfWater = Celsius(fromFahrenheit: 212.0)
// boilingPointOfWater.temperatureInCelsius is 100.0
let freezingPointOfWater = Celsius(fromKelvin: 273.15)
// freezingPointOfWater.temperatureInCelsius is 0.0
初始化函数的参数名在区分初始化方法的时候起到了重要作用,所以 swift 提供了自动扩展名的方法,如果你不提供扩展名,则扩展名跟本地参数名相同。如果不想提供扩展名,则参数名使用下划线 (_) 替代。
如果指定了扩展参数名,则必须使用,否则报编译错误
struct Color {
let red = 0.0, green = 0.0, blue = 0.0
init(red: Double, green: Double, blue: Double) {
self.red = red
self.green = green
self.blue = blue
}
}
let magenta = Color(red: 1.0, green: 0.0, blue: 1.0)
//使用下面方法将会提示编译错误
let veryGreen = Color(0.0, 1.0, 0.0)
如果有可选变量,则可选变量时自动被初始化为 nil 的
即使是常量也可以在初始化时改变其初始值。常量属性也只能在本类的初始化函数中改变,不能在子类的初始化函数中改变
class SurveyQuestion {
let text: String
var response: String?
init(text: String) {
self.text = text
}
func ask() {
println(text)
}
}
let beetsQuestion = SurveyQuestion(text: "How about beets?")
beetsQuestion.ask()
// prints "How about beets?"
beetsQuestion.response = "I also like beets. (But not with cheese.)"
类有默认的构造函数,前提是所有的成员变量都有默认值,则类有一个没有参数,没有函数体的构造函数,类似 C 的默认构造函数,初始化其成员的值为默认值,并生成一个实例
结构体的成员构造函数,结构体的成员有初始值,并且没有定义构造函数时,结构体自动提供成员变量的构造函数:
struct Size {
var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
一个构造函数可以调用其他构造函数,这叫做构造代理,使用 self.init。
其中值类型的构造代理比较简单,因为它没有继承,所以只能调用自己的构造函数。在此需要注意,如果你定义了自己的构造函数,则类的默认构造函数和成员构造函数就不可再使用,如果你想既有自己的构造函数,又需要默认构造函数,则需要使用扩展方法。
struct Size {
var width = 0.0, height = 0.0
}
struct Point {
var x = 0.0, y = 0.0
}
struct Rect {
var origin = Point()
var size = Size()
init() {}
init(origin: Point, size: Size) {
self.origin = origin
self.size = size
}
init(center: Point, size: Size) {
let originX = center.x - (size.width / 2)
let originY = center.y - (size.height / 2)
self.init(origin: Point(x: originX, y: originY), size: size)
}
}
let basicRect = Rect()
// basicRect''s origin is (0.0, 0.0) and its size is (0.0, 0.0)
let originRect = Rect(origin: Point(x: 2.0, y: 2.0),
size: Size(width: 5.0, height: 5.0))
// originRect''s origin is (2.0, 2.0) and its size is (5.0, 5.0)
let centerRect = Rect(center: Point(x: 4.0, y: 4.0),
size: Size(width: 3.0, height: 3.0))
// centerRect''s origin is (2.5, 2.5) and its size is (3.0, 3.0)
Rect 有 3 个构造函数,第三个构造函数可以调用第二个构造函数。
指定构造函数就是我们一直使用的构造函数,没有修饰的, 所有类都必须至少有一个的构造函数
便利构造函数是为了方便用户初始化而添加的函数,使用 convenience 修饰的构造函数。
你可以使用任何一个构造函数定义实例。他们的格式为:
//指定构造方法
init(parameters) {
statements
}
//便利构造方法
convenience init(parameters) {
statements
}
指定构造函数和便利构造函数总是遵循下列规则:
1、指定构造函数肯定调用其直接父类的指定构造函数
2、便利构造函数肯定调用本类的其他任意构造函数
3、便利构造函数调用链最后必须以调用指定构造函数结束。
以代理的思想说就是:
指定构造函数总是向上代理,便利构造函数总是横向代理。
编译器为了保证初始化正确进行,将初始化分为两个阶段,第一个阶段保证每个成员的都有其初始值,第二阶段提供给用户根据其需求修改成员的初始值。
编译器为了能正确进行初始化,进行如下 4 项安全检查:
1、指定构造方法在调用父类构造方法前,一定保证其成员都有初始值。
2、指定构造方法一定要在调用父类构造方法后,再给从父类继承的成员赋自定义值,如果不这样的话,你赋的值将被父类构造方法覆盖为父类的初始值。
3、便利构造方法先调用其他构造方法,再给成员变量赋值,否则你的赋值会被指定构造方法覆盖。
4、在第一阶段完成前,构造方法不能使用 self,不能使用实例方法,实例成员。
下面是根据上述 4 项检查,描述构造的两个阶段:
阶段一:
1、一个指定构造方法或者便利构造方法被调用
2、一个实例的内存被分配,但是内存的值还没有被初始化
3、总会有一个指定构造方法被调用,它保证所有存储变量有特定的值,内存的值现在被初始化了
4、这个指定构造方法开始调用父类构造方法,父类的构造方法保证父类本身的每个存储变量被初始化
5、重复步骤 3 和 4,直到最顶层的父类,最顶层的父类的存储变量被初始化后,这个实例的所有的变量也就被初始化完成,标志初始化的第一阶段完成。
阶段二:
6、从最顶层的父类开始,根据用户特殊需求,指定构造方法可以修改变量的值,调用实例方法,可以使用 self。
7、返回第二层父类,再返回第三层父类,最后到达本类的指定构造方法,便利构造方法,便利构造方法此时也可以使用 self,使用成员变量和方法。
构造方法的继承:
swift 不会默认继承父类的构造方法,构造方法的自动继承满足下面规则:
1、如果子类没有定义任何指定构造方法,则子类自动继承所有父类的指定构造方法
2、如果子类提供了所有父类指定构造方法的实现(无论是通过规则 1 实现,还是自定义实现,即使实现为便利构造方法),子类将自动继承父类所有便利构造方法
即使添加了更多便利构造方法,对上面的规则没有影响。
构造方法的重载:
你可以在子类中提供和重载父类的构造函数,如果重载指定构造函数,你可以重写实现和调用父类的这个指定构造函数。如果重载的是便利构造方法,则必须调用本类的一个另一个指定构造方法。
下面是一个示例,分析有助于理解:
class Food {
var name: String
init(name: String) {
self.name = name
}
convenience init() {
self.init(name: "[Unnamed]")
}
}
便利构造方法调用指定构造方法
class RecipeIngredient: Food {
var quantity: Int
init(name: String, quantity: Int) {
self.quantity = quantity
super.init(name: name)
}
convenience init(name: String) {
self.init(name: name, quantity: 1)
}
}
便利构造方法调用指定构造方法,子类的指定构造方法调用父类的指定构造方法
由于便利构造方法 init (name:String) 与父类指定构造方法使用了相同的参数名,所以认为是重写了父类的指定构造函数,所以父类的便利构造函数被自动继承
class ShoppingListItem: RecipeIngredient {
var purchased = false
var description: String {
var output = "\(quantity) x \(name.lowercaseString)"
output += purchased ? " ✔" : " ✘"
return output
}
}
购买清单这个类的成员都有初始值,并且没有自己的构造方法,则继承了父类的所有构造方法
使用方法和闭包设置成员默认值
class SomeClass {
let someProperty: SomeType = {
// create a default value for someProperty inside this closure
// someValue must be of the same type as SomeType
return someValue
}()
}
闭包最后的空括号告诉 swift 直接运行这个闭包,如果没有这个空括号,则表示将一个闭包赋值给 someProperty 了
注意:使用闭包初始化成员的值,不能使用 self 和其他成员,因为这时候实例还没有初始值
c – 使用SFINAE“重载”构造函数
#include <vector> #include <type_traits> namespace xyz { struct MemoryManager{}; template<typename T,typename Alloc=MemoryManager> class vector { }; } template<typename T,template<typename,typename> class V,typename A> struct Foo { template<typename U = T,typename Dummy = typename std::enable_if< std::is_same<std::vector<U>,V<U,A> >::value >::type > Foo() // when instantiated with the std vector { } template<typename U = T,typename Dummy = typename std::enable_if< std::is_same<xyz::vector<U>,A> >::value >::type > Foo() // when instantiated with my custom vector { } }; int main() { }
错误信息:
23:3: error: ‘template<class T,template<class,class> class V,class A> template<class U,class Dummy> Foo<T,V,A>::Foo()’ cannot be overloaded Foo() // when instantiated with my custom vector 18:3: error: with ‘template<class T,A>::Foo()’ Foo() // when instantiated with the std vector
解决方法
template <typename,typename> Foo(); template <typename,typename> Foo();
这个规则可能在模板世界之外更清晰,这两个函数不能相互重载:
void foo(int x = 42); void foo(int y = 17);
您可以改为将第二个模板参数设为默认的非类型参数,以便两个构造函数具有不同的签名:
template<typename U = T,std::enable_if_t<std::is_same<std::vector<U>,V<T,A> >::value,int> = 0> Foo() // when instantiated with the std vector
或者您可以使用虚拟类型委托两个构造函数:
template <typename T> struct tag { }; Foo() : Foo(tag<V<T,A>>{}) { } Foo(tag<std::vector<T>> ) { /* std vector */ } Foo(tag<xyz::vector<T>> ) { /* your vector */ }
c – 错误:为“构造函数”属性指定的参数数量错误
但是,我正面临一个错误.这是代码:
#include <stdlib.h> #include <string.h> #include <stdio.h> #include <iostream> using namespace std; extern "C" void startMe(void) __attribute__ ((constructor(1))); extern "C" void ending(void) __attribute__ ((destructor)); class Test { public: test() { cout << "This is test constructor" << endl; } }; int main() { test(); printf("Now main called\n"); } void startMe(void) { printf("Start me called before main\n"); } void ending(void) { printf("Destructor called\n"); }
–
Output: $g++ constructor1.cc constructor1.cc:10: error: wrong number of arguments specified for ‘constructor’ attribute
但是,当我删除构造函数优先级时,它编译并运行正常.也就是说,我这样做:
extern "C" void startMe(void) __attribute__ ((constructor));
为什么会这样?如何优先考虑?
请帮我.我的想法是首先执行“ctor”,然后执行另一个(Test)构造函数.同样的原因,我把ctor作为优先事项1.
解决方法
warning: constructor priorities from 0 to 100 are reserved for the implementation
将优先级从1更改为101可以消除警告并且可执行文件生成:
Start me called before main This is test constructor Now main called Destructor called
这是使用GCC 4.5
c# – 构造函数/析构函数链接错误
但是,当我将这个test.dll(或者我的情况下的.lib,因为我使用Visual Studio)链接到我们的生产模块中的项目时,我得到奇怪的链接错误指向它无法为TestClass找到的构造函数和析构函数.我知道我不会调用new / delete,或者在项目的任何地方创建任何TestClass的堆栈实例.生产模块使用C#/ CLR / CLI以及C.解决方法的唯一方法是为我导出TestClass的构造函数和析构函数.这在设计上是不合需要的.
这种情况对任何人都很熟悉吗?有人可以指出可能存在的问题吗?
这是我得到的错误:
Error 5264 error LNK2028: unresolved token (0A000BA3) "public: virtual __thiscall BE::TestClass::~TestClass(void)" (??1TestClass@BE@@$$FUAE@XZ) referenced in function "public: virtual void * __thiscall BE::TestClass::`vector deleting destructor'(unsigned int)" (??_ETestClass@BE@@$$FUAEpaxI@Z) AMBestDetailBridge.obj BEBase Error 5373 error LNK2001: unresolved external symbol "public: virtual __thiscall BE::TestClass::~TestClass(void)" (??1TestClass@BE@@$$FUAE@XZ) AMBestDetailBridge.obj BEBase
谢谢!
解决方法
TestClass* pTest = ... delete pTest; TestClass* pTestArray = ... delete[] pTest;
当然,在智能指针的情况下,它可能不是那么明显:
SmartPtr<TestClass> spTest = ... // delete called automatically when out of scope.
在一个模块中分配并在另一个模块中删除会使自己面临潜在的风险 – 因为2个模块可能使用不同的堆进行内存分配(比如重新定义新的运算符),幸运的是这个问题在链接时暴露,而不是在运行时暴露.
C#构造函数
using System;
namespace LineApplication {
class Line {
private double length; // Length of a line
public Line() {
Console.WriteLine(Object is being created);
}
public void setLength( double len ) {
length = len;
}
public double getLength() {
return length;
}
static void Main(string[] args) {
Line line = new Line();
// set line length
line.setLength(6.0);
Console.WriteLine(Length of line : {0}, line.getLength());
Console.ReadKey();
}
}
}
今天关于swift (14) 构造函数和构造函数=default的分享就到这里,希望大家有所收获,若想了解更多关于c – 使用SFINAE“重载”构造函数、c – 错误:为“构造函数”属性指定的参数数量错误、c# – 构造函数/析构函数链接错误、C#构造函数等相关知识,可以在本站进行查询。
本文标签: